Browse Source

Merge #8085: p2p: Begin encapsulation

0103c5b net: move MAX_FEELER_CONNECTIONS into connman (Cory Fields)
e700cd0 Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead (Jeremy Rubin)
d1a2295 Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting (Jeremy Rubin)
98591c5 net: move vNodesDisconnected into CConnman (Cory Fields)
fa2f8bc net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options (Cory Fields)
a19553b net: Introduce CConnection::Options to avoid passing so many params (Cory Fields)
bafa5fc net: Drop StartNode/StopNode and use CConnman directly (Cory Fields)
e81a602 net: pass CClientUIInterface into CConnman (Cory Fields)
f60b905 net: Pass best block known height into CConnman (Cory Fields)
fdf69ff net: move max/max-outbound to CConnman (Cory Fields)
8a59369 net: move semOutbound to CConnman (Cory Fields)
bd72937 net: move nLocalServices/nRelevantServices to CConnman (Cory Fields)
be9c796 net: move SendBufferSize/ReceiveFloodSize to CConnman (Cory Fields)
63cafa6 net: move send/recv statistics to CConnman (Cory Fields)
adf5d4c net: SocketSendData returns written size (Cory Fields)
ee44fa9 net: move messageHandlerCondition to CConnman (Cory Fields)
960cf2e net: move nLocalHostNonce to CConnman (Cory Fields)
551e088 net: move nLastNodeId to CConnman (Cory Fields)
6c19d92 net: move whitelist functions into CConnman (Cory Fields)
53347f0 net: create generic functor accessors and move vNodes to CConnman (Cory Fields)
c0569c7 net: Add most functions needed for vNodes to CConnman (Cory Fields)
8ae2dac net: move added node functions to CConnman (Cory Fields)
502dd3a net: Add oneshot functions to CConnman (Cory Fields)
a0f3d3c net: move ban and addrman functions into CConnman (Cory Fields)
aaf018e net: handle nodesignals in CConnman (Cory Fields)
b1a5f43 net: move OpenNetworkConnection into CConnman (Cory Fields)
02137f1 net: Move socket binding into CConnman (Cory Fields)
5b446dd net: Pass CConnection to wallet rather than using the global (Cory Fields)
8d58c4d net: Pass CConnman around as needed (Cory Fields)
d7349ca net: Add rpc error for missing/disabled p2p functionality (Cory Fields)
cd16f48 net: Create CConnman to encapsulate p2p connections (Cory Fields)
d93b14d net: move CBanDB and CAddrDB out of net.h/cpp (Cory Fields)
531214f gui: add NodeID to the peer table (Cory Fields)
0.14
Wladimir J. van der Laan 8 years ago
parent
commit
6423116741
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 2
      src/Makefile.am
  2. 218
      src/addrdb.cpp
  3. 103
      src/addrdb.h
  4. 54
      src/init.cpp
  5. 169
      src/main.cpp
  6. 10
      src/main.h
  7. 803
      src/net.cpp
  8. 544
      src/net.h
  9. 3
      src/qt/bantablemodel.cpp
  10. 26
      src/qt/clientmodel.cpp
  11. 8
      src/qt/guiutil.cpp
  12. 2
      src/qt/guiutil.h
  13. 21
      src/qt/peertablemodel.cpp
  14. 7
      src/qt/peertablemodel.h
  15. 41
      src/qt/rpcconsole.cpp
  16. 2
      src/qt/walletmodel.cpp
  17. 4
      src/rpc/blockchain.cpp
  18. 9
      src/rpc/mining.cpp
  19. 11
      src/rpc/misc.cpp
  20. 108
      src/rpc/net.cpp
  21. 1
      src/rpc/protocol.h
  22. 8
      src/rpc/rawtransaction.cpp
  23. 56
      src/test/DoS_tests.cpp
  24. 2
      src/test/miner_tests.cpp
  25. 6
      src/test/net_tests.cpp
  26. 8
      src/test/test_bitcoin.cpp
  27. 2
      src/test/test_bitcoin.h
  28. 4
      src/validationinterface.cpp
  29. 5
      src/validationinterface.h
  30. 15
      src/wallet/rpcwallet.cpp
  31. 24
      src/wallet/wallet.cpp
  32. 8
      src/wallet/wallet.h

2
src/Makefile.am

@ -71,6 +71,7 @@ endif
.PHONY: FORCE check-symbols check-security .PHONY: FORCE check-symbols check-security
# bitcoin core # # bitcoin core #
BITCOIN_CORE_H = \ BITCOIN_CORE_H = \
addrdb.h \
addrman.h \ addrman.h \
base58.h \ base58.h \
bloom.h \ bloom.h \
@ -164,6 +165,7 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \ libbitcoin_server_a_SOURCES = \
addrman.cpp \ addrman.cpp \
addrdb.cpp \
bloom.cpp \ bloom.cpp \
blockencodings.cpp \ blockencodings.cpp \
chain.cpp \ chain.cpp \

218
src/addrdb.cpp

@ -0,0 +1,218 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "addrdb.h"
#include "addrman.h"
#include "chainparams.h"
#include "clientversion.h"
#include "hash.h"
#include "random.h"
#include "streams.h"
#include "tinyformat.h"
#include "util.h"
#include <boost/filesystem.hpp>
CBanDB::CBanDB()
{
pathBanlist = GetDataDir() / "banlist.dat";
}
bool CBanDB::Write(const banmap_t& banSet)
{
// Generate random temporary filename
unsigned short randv = 0;
GetRandBytes((unsigned char*)&randv, sizeof(randv));
std::string tmpfn = strprintf("banlist.dat.%04x", randv);
// serialize banlist, checksum data up to that point, then append csum
CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);
ssBanlist << FLATDATA(Params().MessageStart());
ssBanlist << banSet;
uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());
ssBanlist << hash;
// open temp output file, and associate with CAutoFile
boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
FILE *file = fopen(pathTmp.string().c_str(), "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s: Failed to open file %s", __func__, pathTmp.string());
// Write and commit header, data
try {
fileout << ssBanlist;
}
catch (const std::exception& e) {
return error("%s: Serialize or I/O error - %s", __func__, e.what());
}
FileCommit(fileout.Get());
fileout.fclose();
// replace existing banlist.dat, if any, with new banlist.dat.XXXX
if (!RenameOver(pathTmp, pathBanlist))
return error("%s: Rename-into-place failed", __func__);
return true;
}
bool CBanDB::Read(banmap_t& banSet)
{
// open input file, and associate with CAutoFile
FILE *file = fopen(pathBanlist.string().c_str(), "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("%s: Failed to open file %s", __func__, pathBanlist.string());
// use file size to size memory buffer
uint64_t fileSize = boost::filesystem::file_size(pathBanlist);
uint64_t dataSize = 0;
// Don't try to resize to a negative number if file is small
if (fileSize >= sizeof(uint256))
dataSize = fileSize - sizeof(uint256);
std::vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
// read data and checksum from file
try {
filein.read((char *)&vchData[0], dataSize);
filein >> hashIn;
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
filein.fclose();
CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION);
// verify stored checksum matches input data
uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end());
if (hashIn != hashTmp)
return error("%s: Checksum mismatch, data corrupted", __func__);
unsigned char pchMsgTmp[4];
try {
// de-serialize file header (network specific magic number) and ..
ssBanlist >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s: Invalid network magic number", __func__);
// de-serialize address data into one CAddrMan object
ssBanlist >> banSet;
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
return true;
}
CAddrDB::CAddrDB()
{
pathAddr = GetDataDir() / "peers.dat";
}
bool CAddrDB::Write(const CAddrMan& addr)
{
// Generate random temporary filename
unsigned short randv = 0;
GetRandBytes((unsigned char*)&randv, sizeof(randv));
std::string tmpfn = strprintf("peers.dat.%04x", randv);
// serialize addresses, checksum data up to that point, then append csum
CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
ssPeers << FLATDATA(Params().MessageStart());
ssPeers << addr;
uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
ssPeers << hash;
// open temp output file, and associate with CAutoFile
boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
FILE *file = fopen(pathTmp.string().c_str(), "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s: Failed to open file %s", __func__, pathTmp.string());
// Write and commit header, data
try {
fileout << ssPeers;
}
catch (const std::exception& e) {
return error("%s: Serialize or I/O error - %s", __func__, e.what());
}
FileCommit(fileout.Get());
fileout.fclose();
// replace existing peers.dat, if any, with new peers.dat.XXXX
if (!RenameOver(pathTmp, pathAddr))
return error("%s: Rename-into-place failed", __func__);
return true;
}
bool CAddrDB::Read(CAddrMan& addr)
{
// open input file, and associate with CAutoFile
FILE *file = fopen(pathAddr.string().c_str(), "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("%s: Failed to open file %s", __func__, pathAddr.string());
// use file size to size memory buffer
uint64_t fileSize = boost::filesystem::file_size(pathAddr);
uint64_t dataSize = 0;
// Don't try to resize to a negative number if file is small
if (fileSize >= sizeof(uint256))
dataSize = fileSize - sizeof(uint256);
std::vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
// read data and checksum from file
try {
filein.read((char *)&vchData[0], dataSize);
filein >> hashIn;
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
filein.fclose();
CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
// verify stored checksum matches input data
uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
if (hashIn != hashTmp)
return error("%s: Checksum mismatch, data corrupted", __func__);
return Read(addr, ssPeers);
}
bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
{
unsigned char pchMsgTmp[4];
try {
// de-serialize file header (network specific magic number) and ..
ssPeers >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s: Invalid network magic number", __func__);
// de-serialize address data into one CAddrMan object
ssPeers >> addr;
}
catch (const std::exception& e) {
// de-serialization has failed, ensure addrman is left in a clean state
addr.Clear();
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
return true;
}

103
src/addrdb.h

@ -0,0 +1,103 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_ADDRDB_H
#define BITCOIN_ADDRDB_H
#include "serialize.h"
#include <string>
#include <map>
#include <boost/filesystem/path.hpp>
class CSubNet;
class CAddrMan;
class CDataStream;
typedef enum BanReason
{
BanReasonUnknown = 0,
BanReasonNodeMisbehaving = 1,
BanReasonManuallyAdded = 2
} BanReason;
class CBanEntry
{
public:
static const int CURRENT_VERSION=1;
int nVersion;
int64_t nCreateTime;
int64_t nBanUntil;
uint8_t banReason;
CBanEntry()
{
SetNull();
}
CBanEntry(int64_t nCreateTimeIn)
{
SetNull();
nCreateTime = nCreateTimeIn;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(nCreateTime);
READWRITE(nBanUntil);
READWRITE(banReason);
}
void SetNull()
{
nVersion = CBanEntry::CURRENT_VERSION;
nCreateTime = 0;
nBanUntil = 0;
banReason = BanReasonUnknown;
}
std::string banReasonToString()
{
switch (banReason) {
case BanReasonNodeMisbehaving:
return "node misbehaving";
case BanReasonManuallyAdded:
return "manually added";
default:
return "unknown";
}
}
};
typedef std::map<CSubNet, CBanEntry> banmap_t;
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
{
private:
boost::filesystem::path pathAddr;
public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
class CBanDB
{
private:
boost::filesystem::path pathBanlist;
public:
CBanDB();
bool Write(const banmap_t& banSet);
bool Read(banmap_t& banSet);
};
#endif // BITCOIN_ADDRDB_H

54
src/init.cpp

@ -42,6 +42,7 @@
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <memory>
#ifndef WIN32 #ifndef WIN32
#include <signal.h> #include <signal.h>
@ -70,6 +71,7 @@ static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_DISABLE_SAFEMODE = false; static const bool DEFAULT_DISABLE_SAFEMODE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
std::unique_ptr<CConnman> g_connman;
#if ENABLE_ZMQ #if ENABLE_ZMQ
static CZMQNotificationInterface* pzmqNotificationInterface = NULL; static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
@ -197,7 +199,10 @@ void Shutdown()
if (pwalletMain) if (pwalletMain)
pwalletMain->Flush(false); pwalletMain->Flush(false);
#endif #endif
StopNode(); MapPort(false);
g_connman->Stop();
g_connman.reset();
StopTorControl(); StopTorControl();
UnregisterNodeSignals(GetNodeSignals()); UnregisterNodeSignals(GetNodeSignals());
@ -269,11 +274,11 @@ void HandleSIGHUP(int)
fReopenDebugLog = true; fReopenDebugLog = true;
} }
bool static Bind(const CService &addr, unsigned int flags) { bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {
if (!(flags & BF_EXPLICIT) && IsLimited(addr)) if (!(flags & BF_EXPLICIT) && IsLimited(addr))
return false; return false;
std::string strError; std::string strError;
if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
if (flags & BF_REPORT_ERROR) if (flags & BF_REPORT_ERROR)
return InitError(strError); return InitError(strError);
return false; return false;
@ -864,7 +869,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Make sure enough file descriptors are available // Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0); int nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations // Trim requested connection counts, to fit into system limitations
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
@ -985,6 +990,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Option to startup with mocktime set (used for regression testing): // Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
ServiceFlags nLocalServices = NODE_NETWORK;
ServiceFlags nRelevantServices = NODE_NETWORK;
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
@ -1108,6 +1116,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
// ********************************************************* Step 6: network initialization // ********************************************************* Step 6: network initialization
assert(!g_connman);
g_connman = std::unique_ptr<CConnman>(new CConnman());
CConnman& connman = *g_connman;
RegisterNodeSignals(GetNodeSignals()); RegisterNodeSignals(GetNodeSignals());
// sanitize comments per BIP-0014, format user agent and check total size // sanitize comments per BIP-0014, format user agent and check total size
@ -1145,7 +1157,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LookupSubNet(net.c_str(), subnet); LookupSubNet(net.c_str(), subnet);
if (!subnet.IsValid()) if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
CNode::AddWhitelistedRange(subnet); connman.AddWhitelistedRange(subnet);
} }
} }
@ -1197,7 +1209,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CService addrBind; CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(ResolveErrMsg("bind", strBind)); return InitError(ResolveErrMsg("bind", strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
} }
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) { BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
CService addrBind; CService addrBind;
@ -1205,14 +1217,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError(ResolveErrMsg("whitebind", strBind)); return InitError(ResolveErrMsg("whitebind", strBind));
if (addrBind.GetPort() == 0) if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind)); return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
} }
} }
else { else {
struct in_addr inaddr_any; struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY; inaddr_any.s_addr = INADDR_ANY;
fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE); fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE);
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE); fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
} }
if (!fBound) if (!fBound)
return InitError(_("Failed to listen on any port. Use -listen=0 if you want this.")); return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
@ -1229,7 +1241,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
} }
BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"]) BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest); connman.AddOneShot(strDest);
#if ENABLE_ZMQ #if ENABLE_ZMQ
pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs); pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
@ -1239,7 +1251,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
} }
#endif #endif
if (mapArgs.count("-maxuploadtarget")) { if (mapArgs.count("-maxuploadtarget")) {
CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); connman.SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024);
} }
// ********************************************************* Step 7: load block chain // ********************************************************* Step 7: load block chain
@ -1505,7 +1517,25 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler); StartTorControl(threadGroup, scheduler);
StartNode(threadGroup, scheduler); Discover(threadGroup);
// Map ports with UPnP
MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
std::string strNodeError;
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
connOptions.nRelevantServices = nRelevantServices;
connOptions.nMaxConnections = nMaxConnections;
connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
connOptions.nMaxFeeler = 1;
connOptions.nBestHeight = chainActive.Height();
connOptions.uiInterface = &uiInterface;
connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions))
return InitError(strNodeError);
// ********************************************************* Step 12: finished // ********************************************************* Step 12: finished

169
src/main.cpp

@ -325,12 +325,6 @@ CNodeState *State(NodeId pnode) {
return &it->second; return &it->second;
} }
int GetHeight()
{
LOCK(cs_main);
return chainActive.Height();
}
void UpdatePreferredDownload(CNode* node, CNodeState* state) void UpdatePreferredDownload(CNode* node, CNodeState* state)
{ {
nPreferredDownload -= state->fPreferredDownload; nPreferredDownload -= state->fPreferredDownload;
@ -348,7 +342,8 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) {
state.address = pnode->addr; state.address = pnode->addr;
} }
void FinalizeNode(NodeId nodeid) { void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
fUpdateConnectionTime = false;
LOCK(cs_main); LOCK(cs_main);
CNodeState *state = State(nodeid); CNodeState *state = State(nodeid);
@ -356,7 +351,7 @@ void FinalizeNode(NodeId nodeid) {
nSyncStarted--; nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
AddressCurrentlyConnected(state->address); fUpdateConnectionTime = true;
} }
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) { BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
@ -469,8 +464,8 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
} }
} }
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) { void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) {
if (nLocalServices & NODE_WITNESS) { if (pfrom->GetLocalServices() & NODE_WITNESS) {
// Don't ever request compact blocks when segwit is enabled. // Don't ever request compact blocks when segwit is enabled.
return; return;
} }
@ -483,11 +478,12 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce // As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings. // blocks using compact encodings.
CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front()); bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
if (pnodeStop) {
pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
return true;
});
if(found)
lNodesAnnouncingHeaderAndIDs.pop_front(); lNodesAnnouncingHeaderAndIDs.pop_front();
}
} }
fAnnounceUsingCMPCTBLOCK = true; fAnnounceUsingCMPCTBLOCK = true;
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
@ -637,7 +633,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
void RegisterNodeSignals(CNodeSignals& nodeSignals) void RegisterNodeSignals(CNodeSignals& nodeSignals)
{ {
nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages); nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages); nodeSignals.SendMessages.connect(&SendMessages);
nodeSignals.InitializeNode.connect(&InitializeNode); nodeSignals.InitializeNode.connect(&InitializeNode);
@ -646,7 +641,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals)
void UnregisterNodeSignals(CNodeSignals& nodeSignals) void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{ {
nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages); nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages); nodeSignals.SendMessages.disconnect(&SendMessages);
nodeSignals.InitializeNode.disconnect(&InitializeNode); nodeSignals.InitializeNode.disconnect(&InitializeNode);
@ -3016,7 +3010,7 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either NULL or a pointer to a block * or an activated best chain. pblock is either NULL or a pointer to a block
* that is already loaded (to avoid loading it again from disk). * that is already loaded (to avoid loading it again from disk).
*/ */
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, CConnman* connman) {
CBlockIndex *pindexMostWork = NULL; CBlockIndex *pindexMostWork = NULL;
CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexNewTip = NULL;
do { do {
@ -3056,6 +3050,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
// When we reach this point, we switched to a new tip (stored in pindexNewTip). // When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main // Notifications/callbacks that can run without cs_main
if(connman)
connman->SetBestHeight(nNewHeight);
// throw all transactions though the signal-interface // throw all transactions though the signal-interface
// while _not_ holding the cs_main lock // while _not_ holding the cs_main lock
@ -3088,15 +3084,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
int nBlockEstimate = 0; int nBlockEstimate = 0;
if (fCheckpointsEnabled) if (fCheckpointsEnabled)
nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
{ if(connman) {
LOCK(cs_vNodes); connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) {
BOOST_FOREACH(CNode* pnode, vNodes) {
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
pnode->PushBlockHash(hash); pnode->PushBlockHash(hash);
} }
} }
} });
} }
// Notify external listeners about the new tip. // Notify external listeners about the new tip.
if (!vHashes.empty()) { if (!vHashes.empty()) {
@ -3731,7 +3726,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
return true; return true;
} }
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp) bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman)
{ {
{ {
LOCK(cs_main); LOCK(cs_main);
@ -3753,7 +3748,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
NotifyHeaderTip(); NotifyHeaderTip();
if (!ActivateBestChain(state, chainparams, pblock)) if (!ActivateBestChain(state, chainparams, pblock, connman))
return error("%s: ActivateBestChain failed", __func__); return error("%s: ActivateBestChain failed", __func__);
return true; return true;
@ -4725,9 +4720,47 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return true; return true;
} }
void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) static void RelayTransaction(const CTransaction& tx, CConnman& connman)
{
CInv inv(MSG_TX, tx.GetHash());
connman.ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
}
static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
{
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
// Relay to a limited number of other nodes
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max());
static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max());
uint64_t hashAddr = addr.GetHash();
std::multimap<uint64_t, CNode*> mapMix;
const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
auto sortfunc = [&mapMix, &hasher](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION) {
uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
mapMix.emplace(hashKey, pnode);
}
};
auto pushfunc = [&addr, &mapMix, &nRelayNodes] {
for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
mi->second->PushAddress(addr);
};
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman)
{ {
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin(); std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
vector<CInv> vNotFound; vector<CInv> vNotFound;
@ -4735,7 +4768,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
while (it != pfrom->vRecvGetData.end()) { while (it != pfrom->vRecvGetData.end()) {
// Don't bother if send buffer is too full to respond anyway // Don't bother if send buffer is too full to respond anyway
if (pfrom->nSendSize >= SendBufferSize()) if (pfrom->nSendSize >= nMaxSendBufferSize)
break; break;
const CInv &inv = *it; const CInv &inv = *it;
@ -4767,7 +4800,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// disconnect node in case we have reached the outbound limit for serving historical blocks // disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes // never disconnect whitelisted nodes
static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical
if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
{ {
LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
@ -4891,8 +4924,10 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params
return nFetchFlags; return nFetchFlags;
} }
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams) bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman)
{ {
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{ {
@ -4901,7 +4936,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
if (!(nLocalServices & NODE_BLOOM) && if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
(strCommand == NetMsgType::FILTERLOAD || (strCommand == NetMsgType::FILTERLOAD ||
strCommand == NetMsgType::FILTERADD || strCommand == NetMsgType::FILTERADD ||
strCommand == NetMsgType::FILTERCLEAR)) strCommand == NetMsgType::FILTERCLEAR))
@ -4943,7 +4978,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->nServices = ServiceFlags(nServiceInt); pfrom->nServices = ServiceFlags(nServiceInt);
if (!pfrom->fInbound) if (!pfrom->fInbound)
{ {
addrman.SetServices(pfrom->addr, pfrom->nServices); connman.SetServices(pfrom->addr, pfrom->nServices);
} }
if (pfrom->nServicesExpected & ~pfrom->nServices) if (pfrom->nServicesExpected & ~pfrom->nServices)
{ {
@ -4984,7 +5019,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
// Disconnect if we connected to ourself // Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1) if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
{ {
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true; pfrom->fDisconnect = true;
@ -5024,7 +5059,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Advertise our address // Advertise our address
if (fListen && !IsInitialBlockDownload()) if (fListen && !IsInitialBlockDownload())
{ {
CAddress addr = GetLocalAddress(&pfrom->addr); CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
if (addr.IsRoutable()) if (addr.IsRoutable())
{ {
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
@ -5037,12 +5072,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
// Get recent addresses // Get recent addresses
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
{ {
pfrom->PushMessage(NetMsgType::GETADDR); pfrom->PushMessage(NetMsgType::GETADDR);
pfrom->fGetAddr = true; pfrom->fGetAddr = true;
} }
addrman.Good(pfrom->addr); connman.MarkAddressGood(pfrom->addr);
} }
pfrom->fSuccessfullyConnected = true; pfrom->fSuccessfullyConnected = true;
@ -5107,7 +5142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> vAddr; vRecv >> vAddr;
// Don't want addr from older versions unless seeding // Don't want addr from older versions unless seeding
if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)
return true; return true;
if (vAddr.size() > 1000) if (vAddr.size() > 1000)
{ {
@ -5134,32 +5169,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{ {
// Relay to a limited number of other nodes // Relay to a limited number of other nodes
{ RelayAddress(addr, fReachable, connman);
LOCK(cs_vNodes);
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max());
static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max());
uint64_t hashAddr = addr.GetHash();
multimap<uint64_t, CNode*> mapMix;
const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->nVersion < CADDR_TIME_VERSION)
continue;
uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
mapMix.insert(make_pair(hashKey, pnode));
}
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
for (multimap<uint64_t, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr);
}
} }
// Do not store addresses outside our network // Do not store addresses outside our network
if (fReachable) if (fReachable)
vAddrOk.push_back(addr); vAddrOk.push_back(addr);
} }
addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60); connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000) if (vAddr.size() < 1000)
pfrom->fGetAddr = false; pfrom->fGetAddr = false;
if (pfrom->fOneShot) if (pfrom->fOneShot)
@ -5238,7 +5254,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { (!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
inv.type |= nFetchFlags; inv.type |= nFetchFlags;
if (nodestate->fProvidesHeaderAndIDs && !(nLocalServices & NODE_WITNESS)) if (nodestate->fProvidesHeaderAndIDs && !(pfrom->GetLocalServices() & NODE_WITNESS))
vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash)); vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash));
else else
vToFetch.push_back(inv); vToFetch.push_back(inv);
@ -5261,7 +5277,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Track requests for our stuff // Track requests for our stuff
GetMainSignals().Inventory(inv.hash); GetMainSignals().Inventory(inv.hash);
if (pfrom->nSendSize > (SendBufferSize() * 2)) { if (pfrom->nSendSize > (nMaxSendBufferSize * 2)) {
Misbehaving(pfrom->GetId(), 50); Misbehaving(pfrom->GetId(), 50);
return error("send buffer size() = %u", pfrom->nSendSize); return error("send buffer size() = %u", pfrom->nSendSize);
} }
@ -5290,7 +5306,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id);
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom, chainparams.GetConsensus()); ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
} }
@ -5447,7 +5463,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
mempool.check(pcoinsTip); mempool.check(pcoinsTip);
RelayTransaction(tx); RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) { for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i); vWorkQueue.emplace_back(inv.hash, i);
} }
@ -5484,7 +5500,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
continue; continue;
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx); RelayTransaction(orphanTx, connman);
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) { for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
vWorkQueue.emplace_back(orphanHash, i); vWorkQueue.emplace_back(orphanHash, i);
} }
@ -5565,7 +5581,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0; int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) { if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
RelayTransaction(tx); RelayTransaction(tx, connman);
} else { } else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
} }
@ -5684,7 +5700,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
txn.blockhash = cmpctblock.header.GetHash(); txn.blockhash = cmpctblock.header.GetHash();
CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION); CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
blockTxnMsg << txn; blockTxnMsg << txn;
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams); return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
} else { } else {
req.blockhash = pindex->GetBlockHash(); req.blockhash = pindex->GetBlockHash();
pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req); pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req);
@ -5705,7 +5721,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
headers.push_back(cmpctblock.header); headers.push_back(cmpctblock.header);
CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION); CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
vHeadersMsg << headers; vHeadersMsg << headers;
return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams); return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
} }
} }
@ -5741,7 +5757,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->PushMessage(NetMsgType::GETDATA, invs); pfrom->PushMessage(NetMsgType::GETDATA, invs);
} else { } else {
CValidationState state; CValidationState state;
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL); ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, &connman);
int nDoS; int nDoS;
if (state.IsInvalid(nDoS)) { if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@ -5886,10 +5902,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
} }
if (vGetData.size() > 0) { if (vGetData.size() > 0) {
if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) { if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(pfrom->GetLocalServices() & NODE_WITNESS)) {
// We seem to be rather well-synced, so it appears pfrom was the first to provide us // We seem to be rather well-synced, so it appears pfrom was the first to provide us
// with this block! Let's get them to announce using compact blocks in the future. // with this block! Let's get them to announce using compact blocks in the future.
MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom); MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman);
// In any case, we want to download using a compact block, not a regular one // In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
} }
@ -5917,7 +5933,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Such an unrequested block may still be processed, subject to the // Such an unrequested block may still be processed, subject to the
// conditions in AcceptBlock(). // conditions in AcceptBlock().
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman);
int nDoS; int nDoS;
if (state.IsInvalid(nDoS)) { if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@ -5953,7 +5969,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fSentAddr = true; pfrom->fSentAddr = true;
pfrom->vAddrToSend.clear(); pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr(); vector<CAddress> vAddr = connman.GetAddresses();
BOOST_FOREACH(const CAddress &addr, vAddr) BOOST_FOREACH(const CAddress &addr, vAddr)
pfrom->PushAddress(addr); pfrom->PushAddress(addr);
} }
@ -5961,14 +5977,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::MEMPOOL) else if (strCommand == NetMsgType::MEMPOOL)
{ {
if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted) if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
{ {
LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId()); LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true; pfrom->fDisconnect = true;
return true; return true;
} }
if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted)
{ {
LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true; pfrom->fDisconnect = true;
@ -6167,9 +6183,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
// requires LOCK(cs_vRecvMsg) // requires LOCK(cs_vRecvMsg)
bool ProcessMessages(CNode* pfrom) bool ProcessMessages(CNode* pfrom, CConnman& connman)
{ {
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
//if (fDebug) //if (fDebug)
// LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
@ -6184,7 +6201,7 @@ bool ProcessMessages(CNode* pfrom)
bool fOk = true; bool fOk = true;
if (!pfrom->vRecvGetData.empty()) if (!pfrom->vRecvGetData.empty())
ProcessGetData(pfrom, chainparams.GetConsensus()); ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
// this maintains the order of responses // this maintains the order of responses
if (!pfrom->vRecvGetData.empty()) return fOk; if (!pfrom->vRecvGetData.empty()) return fOk;
@ -6192,7 +6209,7 @@ bool ProcessMessages(CNode* pfrom)
std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin(); std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
// Don't bother if send buffer is too full to respond anyway // Don't bother if send buffer is too full to respond anyway
if (pfrom->nSendSize >= SendBufferSize()) if (pfrom->nSendSize >= nMaxSendBufferSize)
break; break;
// get next message // get next message
@ -6244,7 +6261,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false; bool fRet = false;
try try
{ {
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams); fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman);
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
catch (const std::ios_base::failure& e) catch (const std::ios_base::failure& e)
@ -6309,7 +6326,7 @@ public:
} }
}; };
bool SendMessages(CNode* pto) bool SendMessages(CNode* pto, CConnman& connman)
{ {
const Consensus::Params& consensusParams = Params().GetConsensus(); const Consensus::Params& consensusParams = Params().GetConsensus();
{ {
@ -6396,7 +6413,7 @@ bool SendMessages(CNode* pto)
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
else else
{ {
CNode::Ban(pto->addr, BanReasonNodeMisbehaving); connman.Ban(pto->addr, BanReasonNodeMisbehaving);
} }
} }
state.fShouldBan = false; state.fShouldBan = false;
@ -6435,7 +6452,7 @@ bool SendMessages(CNode* pto)
// transactions become unconfirmed and spams other nodes. // transactions become unconfirmed and spams other nodes.
if (!fReindex && !fImporting && !IsInitialBlockDownload()) if (!fReindex && !fImporting && !IsInitialBlockDownload())
{ {
GetMainSignals().Broadcast(nTimeBestReceived); GetMainSignals().Broadcast(nTimeBestReceived, &connman);
} }
// //

10
src/main.h

@ -34,6 +34,7 @@ class CBlockTreeDB;
class CBloomFilter; class CBloomFilter;
class CChainParams; class CChainParams;
class CInv; class CInv;
class CConnman;
class CScriptCheck; class CScriptCheck;
class CTxMemPool; class CTxMemPool;
class CValidationInterface; class CValidationInterface;
@ -222,7 +223,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
* @return True if state.IsValid() * @return True if state.IsValid()
*/ */
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp); bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman);
/** Check whether enough disk space is available for an incoming block */ /** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */ /** Open a block file (blk?????.dat) */
@ -240,13 +241,14 @@ bool LoadBlockIndex();
/** Unload database information */ /** Unload database information */
void UnloadBlockIndex(); void UnloadBlockIndex();
/** Process protocol messages received from a given node */ /** Process protocol messages received from a given node */
bool ProcessMessages(CNode* pfrom); bool ProcessMessages(CNode* pfrom, CConnman& connman);
/** /**
* Send queued protocol messages to be sent to a give node. * Send queued protocol messages to be sent to a give node.
* *
* @param[in] pto The node which we are sending messages to. * @param[in] pto The node which we are sending messages to.
* @param[in] connman The connection manager for that node.
*/ */
bool SendMessages(CNode* pto); bool SendMessages(CNode* pto, CConnman& connman);
/** Run an instance of the script checking thread */ /** Run an instance of the script checking thread */
void ThreadScriptCheck(); void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */ /** Check whether we are doing an initial block download (synchronizing from disk or network) */
@ -262,7 +264,7 @@ std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */ /** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */ /** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, CConnman* connman = NULL);
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
/** /**

803
src/net.cpp

File diff suppressed because it is too large Load Diff

544
src/net.h

@ -6,6 +6,8 @@
#ifndef BITCOIN_NET_H #ifndef BITCOIN_NET_H
#define BITCOIN_NET_H #define BITCOIN_NET_H
#include "addrdb.h"
#include "addrman.h"
#include "amount.h" #include "amount.h"
#include "bloom.h" #include "bloom.h"
#include "compat.h" #include "compat.h"
@ -20,6 +22,7 @@
#include <atomic> #include <atomic>
#include <deque> #include <deque>
#include <stdint.h> #include <stdint.h>
#include <memory>
#ifndef WIN32 #ifndef WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
@ -51,6 +54,8 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000; static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
/** Maximum length of strSubVer in `version` message */ /** Maximum length of strSubVer in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256; static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** Maximum number of outgoing nodes */
static const int MAX_OUTBOUND_CONNECTIONS = 8;
/** -listen default */ /** -listen default */
static const bool DEFAULT_LISTEN = true; static const bool DEFAULT_LISTEN = true;
/** -upnp default */ /** -upnp default */
@ -79,25 +84,317 @@ static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
// NOTE: When adjusting this, update rpcnet:setban's help ("24h") // NOTE: When adjusting this, update rpcnet:setban's help ("24h")
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
typedef int NodeId; typedef int NodeId;
void AddOneShot(const std::string& strDest); struct AddedNodeInfo
void AddressCurrentlyConnected(const CService& addr); {
CNode* FindNode(const CNetAddr& ip); std::string strAddedNode;
CNode* FindNode(const CSubNet& subNet); CService resolvedAddress;
CNode* FindNode(const std::string& addrName); bool fConnected;
CNode* FindNode(const CService& ip); bool fInbound;
CNode* FindNode(const NodeId id); //TODO: Remove this };
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
class CTransaction;
class CNodeStats;
class CClientUIInterface;
class CConnman
{
public:
enum NumConnections {
CONNECTIONS_NONE = 0,
CONNECTIONS_IN = (1U << 0),
CONNECTIONS_OUT = (1U << 1),
CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
};
struct Options
{
ServiceFlags nLocalServices = NODE_NONE;
ServiceFlags nRelevantServices = NODE_NONE;
int nMaxConnections = 0;
int nMaxOutbound = 0;
int nMaxFeeler = 0;
int nBestHeight = 0;
CClientUIInterface* uiInterface = nullptr;
unsigned int nSendBufferMaxSize = 0;
unsigned int nReceiveFloodSize = 0;
};
CConnman();
~CConnman();
bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options options);
void Stop();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
template<typename Callable>
bool ForEachNodeContinueIf(Callable&& func)
{
LOCK(cs_vNodes);
for (auto&& node : vNodes)
if(!func(node))
return false;
return true;
};
template<typename Callable>
bool ForEachNodeContinueIf(Callable&& func) const
{
LOCK(cs_vNodes);
for (const auto& node : vNodes)
if(!func(node))
return false;
return true;
};
template<typename Callable, typename CallableAfter>
bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post)
{
bool ret = true;
LOCK(cs_vNodes);
for (auto&& node : vNodes)
if(!pre(node)) {
ret = false;
break;
}
post();
return ret;
};
template<typename Callable, typename CallableAfter>
bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post) const
{
bool ret = true;
LOCK(cs_vNodes);
for (const auto& node : vNodes)
if(!pre(node)) {
ret = false;
break;
}
post();
return ret;
};
template<typename Callable>
void ForEachNode(Callable&& func)
{
LOCK(cs_vNodes);
for (auto&& node : vNodes)
func(node);
};
template<typename Callable>
void ForEachNode(Callable&& func) const
{
LOCK(cs_vNodes);
for (const auto& node : vNodes)
func(node);
};
template<typename Callable, typename CallableAfter>
void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
{
LOCK(cs_vNodes);
for (auto&& node : vNodes)
pre(node);
post();
};
template<typename Callable, typename CallableAfter>
void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
{
LOCK(cs_vNodes);
for (const auto& node : vNodes)
pre(node);
post();
};
void RelayTransaction(const CTransaction& tx);
// Addrman functions
size_t GetAddressCount() const;
void SetServices(const CService &addr, ServiceFlags nServices);
void MarkAddressGood(const CAddress& addr);
void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses();
void AddressCurrentlyConnected(const CService& addr);
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
// badly and disconnect/ban them, but do it in a
// one-coding-mistake-won't-shatter-the-entire-network
// way.
// IMPORTANT: There should be nothing I can give a
// node that it will forward on that will make that
// node's peers drop it. If there is, an attacker
// can isolate a node and/or try to split the network.
// Dropping a node for sending stuff that is invalid
// now but might be valid in a later version is also
// dangerous, because it can cause a network split
// between nodes running old code and nodes running
// new code.
void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
void ClearBanned(); // needed for unit testing
bool IsBanned(CNetAddr ip);
bool IsBanned(CSubNet subnet);
bool Unban(const CNetAddr &ip);
bool Unban(const CSubNet &ip);
void GetBanned(banmap_t &banmap);
void SetBanned(const banmap_t &banmap);
void AddOneShot(const std::string& strDest);
bool AddNode(const std::string& node);
bool RemoveAddedNode(const std::string& node);
std::vector<AddedNodeInfo> GetAddedNodeInfo();
size_t GetNodeCount(NumConnections num);
void GetNodeStats(std::vector<CNodeStats>& vstats);
bool DisconnectAddress(const CNetAddr& addr);
bool DisconnectNode(const std::string& node);
bool DisconnectNode(NodeId id);
bool DisconnectSubnet(const CSubNet& subnet);
unsigned int GetSendBufferSize() const;
void AddWhitelistedRange(const CSubNet &subnet);
ServiceFlags GetLocalServices() const;
//!set the max outbound target in bytes
void SetMaxOutboundTarget(uint64_t limit);
uint64_t GetMaxOutboundTarget();
//!set the timeframe for the max outbound target
void SetMaxOutboundTimeframe(uint64_t timeframe);
uint64_t GetMaxOutboundTimeframe();
//!check if the outbound target is reached
// if param historicalBlockServingLimit is set true, the function will
// response true if the limit for serving historical blocks has been reached
bool OutboundTargetReached(bool historicalBlockServingLimit);
//!response the bytes left in the current max outbound cycle
// in case of no limit, it will always response 0
uint64_t GetOutboundTargetBytesLeft();
//!response the time in second left in the current max outbound cycle
// in case of no limit, it will always response 0
uint64_t GetMaxOutboundTimeLeftInCycle();
uint64_t GetTotalBytesRecv();
uint64_t GetTotalBytesSent();
void SetBestHeight(int height);
int GetBestHeight() const;
private:
struct ListenSocket {
SOCKET socket;
bool whitelisted;
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
};
void ThreadOpenAddedConnections();
void ProcessOneShot();
void ThreadOpenConnections();
void ThreadMessageHandler();
void AcceptConnection(const ListenSocket& hListenSocket);
void ThreadSocketHandler();
void ThreadDNSAddressSeed();
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& addr);
bool AttemptToEvictConnection();
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure);
bool IsWhitelistedRange(const CNetAddr &addr);
void DeleteNode(CNode* pnode);
NodeId GetNewNodeId();
//!check is the banlist has unwritten changes
bool BannedSetIsDirty();
//!set the "dirty" flag for the banlist
void SetBannedSetDirty(bool dirty=true);
//!clean unused entries (if bantime has expired)
void SweepBanned();
void DumpAddresses();
void DumpData();
void DumpBanlist();
unsigned int GetReceiveFloodSize() const;
// Network stats
void RecordBytesRecv(uint64_t bytes);
void RecordBytesSent(uint64_t bytes);
// Network usage totals
CCriticalSection cs_totalBytesRecv;
CCriticalSection cs_totalBytesSent;
uint64_t nTotalBytesRecv;
uint64_t nTotalBytesSent;
// outbound limit & stats
uint64_t nMaxOutboundTotalBytesSentInCycle;
uint64_t nMaxOutboundCycleStartTime;
uint64_t nMaxOutboundLimit;
uint64_t nMaxOutboundTimeframe;
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
std::vector<CSubNet> vWhitelistedRange;
CCriticalSection cs_vWhitelistedRange;
unsigned int nSendBufferMaxSize;
unsigned int nReceiveFloodSize;
std::vector<ListenSocket> vhListenSocket;
banmap_t setBanned;
CCriticalSection cs_setBanned;
bool setBannedIsDirty;
bool fAddressesInitialized;
CAddrMan addrman;
std::deque<std::string> vOneShots;
CCriticalSection cs_vOneShots;
std::vector<std::string> vAddedNodes;
CCriticalSection cs_vAddedNodes;
std::vector<CNode*> vNodes;
std::list<CNode*> vNodesDisconnected;
mutable CCriticalSection cs_vNodes;
std::atomic<NodeId> nLastNodeId;
boost::condition_variable messageHandlerCondition;
/** Services this instance offers */
ServiceFlags nLocalServices;
/** Services this instance cares about */
ServiceFlags nRelevantServices;
CSemaphore *semOutbound;
int nMaxConnections;
int nMaxOutbound;
int nMaxFeeler;
std::atomic<int> nBestHeight;
CClientUIInterface* clientInterface;
};
extern std::unique_ptr<CConnman> g_connman;
void Discover(boost::thread_group& threadGroup);
void MapPort(bool fUseUPnP); void MapPort(bool fUseUPnP);
unsigned short GetListenPort(); unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler); size_t SocketSendData(CNode *pnode);
bool StopNode();
void SocketSendData(CNode *pnode);
struct CombinerAll struct CombinerAll
{ {
@ -117,11 +414,10 @@ struct CombinerAll
// Signals for message handling // Signals for message handling
struct CNodeSignals struct CNodeSignals
{ {
boost::signals2::signal<int ()> GetHeight; boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> ProcessMessages;
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages; boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> SendMessages;
boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode; boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
boost::signals2::signal<void (NodeId)> FinalizeNode; boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;
}; };
@ -152,30 +448,15 @@ bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(enum Network net); bool IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr); bool IsReachable(const CNetAddr &addr);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
extern bool fDiscover; extern bool fDiscover;
extern bool fListen; extern bool fListen;
extern ServiceFlags nLocalServices;
extern ServiceFlags nRelevantServices;
extern bool fRelayTxes; extern bool fRelayTxes;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
/** Maximum number of connections to simultaneously allow (aka connection slots) */
extern int nMaxConnections;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor; extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
extern std::vector<std::string> vAddedNodes;
extern CCriticalSection cs_vAddedNodes;
extern NodeId nLastNodeId;
extern CCriticalSection cs_nLastNodeId;
/** Subversion as sent to the P2P network in `version` messages */ /** Subversion as sent to the P2P network in `version` messages */
extern std::string strSubVersion; extern std::string strSubVersion;
@ -256,67 +537,6 @@ public:
}; };
typedef enum BanReason
{
BanReasonUnknown = 0,
BanReasonNodeMisbehaving = 1,
BanReasonManuallyAdded = 2
} BanReason;
class CBanEntry
{
public:
static const int CURRENT_VERSION=1;
int nVersion;
int64_t nCreateTime;
int64_t nBanUntil;
uint8_t banReason;
CBanEntry()
{
SetNull();
}
CBanEntry(int64_t nCreateTimeIn)
{
SetNull();
nCreateTime = nCreateTimeIn;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(nCreateTime);
READWRITE(nBanUntil);
READWRITE(banReason);
}
void SetNull()
{
nVersion = CBanEntry::CURRENT_VERSION;
nCreateTime = 0;
nBanUntil = 0;
banReason = BanReasonUnknown;
}
std::string banReasonToString()
{
switch (banReason) {
case BanReasonNodeMisbehaving:
return "node misbehaving";
case BanReasonManuallyAdded:
return "manually added";
default:
return "unknown";
}
}
};
typedef std::map<CSubNet, CBanEntry> banmap_t;
/** Information about a peer */ /** Information about a peer */
class CNode class CNode
{ {
@ -328,6 +548,7 @@ public:
CDataStream ssSend; CDataStream ssSend;
size_t nSendSize; // total size of all vSendMsg entries size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent size_t nSendOffset; // offset inside the first vSendMsg already sent
uint64_t nOptimisticBytesWritten;
uint64_t nSendBytes; uint64_t nSendBytes;
std::deque<CSerializeData> vSendMsg; std::deque<CSerializeData> vSendMsg;
CCriticalSection cs_vSend; CCriticalSection cs_vSend;
@ -374,17 +595,6 @@ public:
const uint64_t nKeyedNetGroup; const uint64_t nKeyedNetGroup;
protected: protected:
// Denial-of-service detection/prevention
// Key is IP address, value is banned-until-time
static banmap_t setBanned;
static CCriticalSection cs_setBanned;
static bool setBannedIsDirty;
// 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;
mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapSendBytesPerMsgCmd;
mapMsgCmdSize mapRecvBytesPerMsgCmd; mapMsgCmdSize mapRecvBytesPerMsgCmd;
@ -446,33 +656,28 @@ public:
CAmount lastSentFeeFilter; CAmount lastSentFeeFilter;
int64_t nextSendTimeFeeFilter; int64_t nextSendTimeFeeFilter;
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode(); ~CNode();
private: private:
// Network usage totals
static CCriticalSection cs_totalBytesRecv;
static CCriticalSection cs_totalBytesSent;
static uint64_t nTotalBytesRecv;
static uint64_t nTotalBytesSent;
// outbound limit & stats
static uint64_t nMaxOutboundTotalBytesSentInCycle;
static uint64_t nMaxOutboundCycleStartTime;
static uint64_t nMaxOutboundLimit;
static uint64_t nMaxOutboundTimeframe;
CNode(const CNode&); CNode(const CNode&);
void operator=(const CNode&); void operator=(const CNode&);
static uint64_t CalculateKeyedNetGroup(const CAddress& ad); static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
uint64_t nLocalHostNonce;
ServiceFlags nLocalServices;
int nMyStartingHeight;
public: public:
NodeId GetId() const { NodeId GetId() const {
return id; return id;
} }
uint64_t GetLocalNonce() const {
return nLocalHostNonce;
}
int GetRefCount() int GetRefCount()
{ {
assert(nRefCount >= 0); assert(nRefCount >= 0);
@ -489,7 +694,7 @@ public:
} }
// requires LOCK(cs_vRecvMsg) // requires LOCK(cs_vRecvMsg)
bool ReceiveMsgBytes(const char *pch, unsigned int nBytes); bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);
// requires LOCK(cs_vRecvMsg) // requires LOCK(cs_vRecvMsg)
void SetRecvVersion(int nVersionIn) void SetRecvVersion(int nVersionIn)
@ -749,110 +954,19 @@ public:
void CloseSocketDisconnect(); void CloseSocketDisconnect();
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
// badly and disconnect/ban them, but do it in a
// one-coding-mistake-won't-shatter-the-entire-network
// way.
// IMPORTANT: There should be nothing I can give a
// node that it will forward on that will make that
// node's peers drop it. If there is, an attacker
// can isolate a node and/or try to split the network.
// Dropping a node for sending stuff that is invalid
// now but might be valid in a later version is also
// dangerous, because it can cause a network split
// between nodes running old code and nodes running
// new code.
static void ClearBanned(); // needed for unit testing
static bool IsBanned(CNetAddr ip);
static bool IsBanned(CSubNet subnet);
static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
static bool Unban(const CNetAddr &ip);
static bool Unban(const CSubNet &ip);
static void GetBanned(banmap_t &banmap);
static void SetBanned(const banmap_t &banmap);
//!check is the banlist has unwritten changes
static bool BannedSetIsDirty();
//!set the "dirty" flag for the banlist
static void SetBannedSetDirty(bool dirty=true);
//!clean unused entries (if bantime has expired)
static void SweepBanned();
void copyStats(CNodeStats &stats); void copyStats(CNodeStats &stats);
static bool IsWhitelistedRange(const CNetAddr &ip); ServiceFlags GetLocalServices() const
static void AddWhitelistedRange(const CSubNet &subnet); {
return nLocalServices;
// Network stats }
static void RecordBytesRecv(uint64_t bytes);
static void RecordBytesSent(uint64_t bytes);
static uint64_t GetTotalBytesRecv();
static uint64_t GetTotalBytesSent();
//!set the max outbound target in bytes
static void SetMaxOutboundTarget(uint64_t limit);
static uint64_t GetMaxOutboundTarget();
//!set the timeframe for the max outbound target
static void SetMaxOutboundTimeframe(uint64_t timeframe);
static uint64_t GetMaxOutboundTimeframe();
//!check if the outbound target is reached
// if param historicalBlockServingLimit is set true, the function will
// response true if the limit for serving historical blocks has been reached
static bool OutboundTargetReached(bool historicalBlockServingLimit);
//!response the bytes left in the current max outbound cycle
// in case of no limit, it will always response 0
static uint64_t GetOutboundTargetBytesLeft();
//!response the time in second left in the current max outbound cycle
// in case of no limit, it will always response 0
static uint64_t GetMaxOutboundTimeLeftInCycle();
}; };
class CTransaction;
void RelayTransaction(const CTransaction& tx);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
{
private:
boost::filesystem::path pathAddr;
public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
class CBanDB
{
private:
boost::filesystem::path pathBanlist;
public:
CBanDB();
bool Write(const banmap_t& banSet);
bool Read(banmap_t& banSet);
};
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ /** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds); int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
struct AddedNodeInfo
{
std::string strAddedNode;
CService resolvedAddress;
bool fConnected;
bool fInbound;
};
std::vector<AddedNodeInfo> GetAddedNodeInfo();
#endif // BITCOIN_NET_H #endif // BITCOIN_NET_H

3
src/qt/bantablemodel.cpp

@ -48,7 +48,8 @@ public:
void refreshBanlist() void refreshBanlist()
{ {
banmap_t banMap; banmap_t banMap;
CNode::GetBanned(banMap); if(g_connman)
g_connman->GetBanned(banMap);
cachedBanlist.clear(); cachedBanlist.clear();
#if QT_VERSION >= 0x040700 #if QT_VERSION >= 0x040700

26
src/qt/clientmodel.cpp

@ -50,16 +50,18 @@ ClientModel::~ClientModel()
int ClientModel::getNumConnections(unsigned int flags) const int ClientModel::getNumConnections(unsigned int flags) const
{ {
LOCK(cs_vNodes); CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;
if (flags == CONNECTIONS_ALL) // Shortcut if we want total
return vNodes.size();
int nNum = 0; if(flags == CONNECTIONS_IN)
BOOST_FOREACH(const CNode* pnode, vNodes) connections = CConnman::CONNECTIONS_IN;
if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) else if (flags == CONNECTIONS_OUT)
nNum++; connections = CConnman::CONNECTIONS_OUT;
else if (flags == CONNECTIONS_ALL)
connections = CConnman::CONNECTIONS_ALL;
return nNum; if(g_connman)
return g_connman->GetNodeCount(connections);
return 0;
} }
int ClientModel::getNumBlocks() const int ClientModel::getNumBlocks() const
@ -70,12 +72,16 @@ int ClientModel::getNumBlocks() const
quint64 ClientModel::getTotalBytesRecv() const quint64 ClientModel::getTotalBytesRecv() const
{ {
return CNode::GetTotalBytesRecv(); if(!g_connman)
return 0;
return g_connman->GetTotalBytesRecv();
} }
quint64 ClientModel::getTotalBytesSent() const quint64 ClientModel::getTotalBytesSent() const
{ {
return CNode::GetTotalBytesSent(); if(!g_connman)
return 0;
return g_connman->GetTotalBytesSent();
} }
QDateTime ClientModel::getLastBlockDate() const QDateTime ClientModel::getLastBlockDate() const

8
src/qt/guiutil.cpp

@ -291,17 +291,17 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
} }
} }
QString getEntryData(QAbstractItemView *view, int column, int role) QVariant getEntryData(QAbstractItemView *view, int column, int role)
{ {
if(!view || !view->selectionModel()) if(!view || !view->selectionModel())
return QString(); return QVariant();
QModelIndexList selection = view->selectionModel()->selectedRows(column); QModelIndexList selection = view->selectionModel()->selectedRows(column);
if(!selection.isEmpty()) { if(!selection.isEmpty()) {
// Return first item // Return first item
return (selection.at(0).data(role).toString()); return (selection.at(0).data(role));
} }
return QString(); return QVariant();
} }
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,

2
src/qt/guiutil.h

@ -70,7 +70,7 @@ namespace GUIUtil
@param[in] role Data role to extract from the model @param[in] role Data role to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/ */
QString getEntryData(QAbstractItemView *view, int column, int role); QVariant getEntryData(QAbstractItemView *view, int column, int role);
void setClipboard(const QString& str); void setClipboard(const QString& str);

21
src/qt/peertablemodel.cpp

@ -24,6 +24,8 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
switch(column) switch(column)
{ {
case PeerTableModel::NetNodeId:
return pLeft->nodeid < pRight->nodeid;
case PeerTableModel::Address: case PeerTableModel::Address:
return pLeft->addrName.compare(pRight->addrName) < 0; return pLeft->addrName.compare(pRight->addrName) < 0;
case PeerTableModel::Subversion: case PeerTableModel::Subversion:
@ -52,24 +54,21 @@ public:
void refreshPeers() void refreshPeers()
{ {
{ {
TRY_LOCK(cs_vNodes, lockNodes);
if (!lockNodes)
{
// skip the refresh if we can't immediately get the lock
return;
}
cachedNodeStats.clear(); cachedNodeStats.clear();
std::vector<CNodeStats> vstats;
if(g_connman)
g_connman->GetNodeStats(vstats);
#if QT_VERSION >= 0x040700 #if QT_VERSION >= 0x040700
cachedNodeStats.reserve(vNodes.size()); cachedNodeStats.reserve(vstats.size());
#endif #endif
Q_FOREACH (CNode* pnode, vNodes) Q_FOREACH (const CNodeStats& nodestats, vstats)
{ {
CNodeCombinedStats stats; CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0; stats.nodeStateStats.nMisbehavior = 0;
stats.nodeStateStats.nSyncHeight = -1; stats.nodeStateStats.nSyncHeight = -1;
stats.nodeStateStats.nCommonHeight = -1; stats.nodeStateStats.nCommonHeight = -1;
stats.fNodeStateStatsAvailable = false; stats.fNodeStateStatsAvailable = false;
pnode->copyStats(stats.nodeStats); stats.nodeStats = nodestats;
cachedNodeStats.append(stats); cachedNodeStats.append(stats);
} }
} }
@ -114,7 +113,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
clientModel(parent), clientModel(parent),
timer(0) timer(0)
{ {
columns << tr("Node/Service") << tr("User Agent") << tr("Ping Time"); columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping Time");
priv = new PeerTablePriv(); priv = new PeerTablePriv();
// default to unsorted // default to unsorted
priv->sortColumn = -1; priv->sortColumn = -1;
@ -160,6 +159,8 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
switch(index.column()) switch(index.column())
{ {
case NetNodeId:
return rec->nodeStats.nodeid;
case Address: case Address:
return QString::fromStdString(rec->nodeStats.addrName); return QString::fromStdString(rec->nodeStats.addrName);
case Subversion: case Subversion:

7
src/qt/peertablemodel.h

@ -52,9 +52,10 @@ public:
void stopAutoRefresh(); void stopAutoRefresh();
enum ColumnIndex { enum ColumnIndex {
Address = 0, NetNodeId = 0,
Subversion = 1, Address = 1,
Ping = 2 Subversion = 2,
Ping = 3
}; };
/** @name Methods overridden from QAbstractTableModel /** @name Methods overridden from QAbstractTableModel

41
src/qt/rpcconsole.cpp

@ -876,37 +876,34 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point)
void RPCConsole::disconnectSelectedNode() void RPCConsole::disconnectSelectedNode()
{ {
if(!g_connman)
return;
// Get currently selected peer address // Get currently selected peer address
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); NodeId id = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::NetNodeId).toInt();
// Find the node, disconnect it and clear the selected node // Find the node, disconnect it and clear the selected node
if (CNode *bannedNode = FindNode(strNode.toStdString())) { if(g_connman->DisconnectNode(id))
bannedNode->fDisconnect = true;
clearSelectedNode(); clearSelectedNode();
}
} }
void RPCConsole::banSelectedNode(int bantime) void RPCConsole::banSelectedNode(int bantime)
{ {
if (!clientModel) if (!clientModel || !g_connman)
return; return;
// Get currently selected peer address // Get currently selected peer address
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString();
// Find possible nodes, ban it and clear the selected node // Find possible nodes, ban it and clear the selected node
if (FindNode(strNode.toStdString())) { std::string nStr = strNode.toStdString();
std::string nStr = strNode.toStdString(); std::string addr;
std::string addr; int port = 0;
int port = 0; SplitHostPort(nStr, port, addr);
SplitHostPort(nStr, port, addr);
CNetAddr resolved;
if(!LookupHost(addr.c_str(), resolved, false))
return;
CNode::Ban(resolved, BanReasonManuallyAdded, bantime);
clearSelectedNode(); CNetAddr resolved;
clientModel->getBanTableModel()->refresh(); if(!LookupHost(addr.c_str(), resolved, false))
} return;
g_connman->Ban(resolved, BanReasonManuallyAdded, bantime);
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
} }
void RPCConsole::unbanSelectedNode() void RPCConsole::unbanSelectedNode()
@ -915,13 +912,13 @@ void RPCConsole::unbanSelectedNode()
return; return;
// Get currently selected ban address // Get currently selected ban address
QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address); QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address).toString();
CSubNet possibleSubnet; CSubNet possibleSubnet;
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet); LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
if (possibleSubnet.IsValid()) if (possibleSubnet.IsValid() && g_connman)
{ {
CNode::Unban(possibleSubnet); g_connman->Unban(possibleSubnet);
clientModel->getBanTableModel()->refresh(); clientModel->getBanTableModel()->refresh();
} }
} }

2
src/qt/walletmodel.cpp

@ -328,7 +328,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
} }
CReserveKey *keyChange = transaction.getPossibleKeyChange(); CReserveKey *keyChange = transaction.getPossibleKeyChange();
if(!wallet->CommitTransaction(*newTx, *keyChange)) if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get()))
return TransactionCommitFailed; return TransactionCommitFailed;
CTransaction* t = (CTransaction*)newTx; CTransaction* t = (CTransaction*)newTx;

4
src/rpc/blockchain.cpp

@ -1277,7 +1277,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
} }
if (state.IsValid()) { if (state.IsValid()) {
ActivateBestChain(state, Params()); ActivateBestChain(state, Params(), NULL, g_connman.get());
} }
if (!state.IsValid()) { if (!state.IsValid()) {
@ -1315,7 +1315,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
} }
CValidationState state; CValidationState state;
ActivateBestChain(state, Params()); ActivateBestChain(state, Params(), NULL, g_connman.get());
if (!state.IsValid()) { if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());

9
src/rpc/mining.cpp

@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
continue; continue;
} }
CValidationState state; CValidationState state;
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, g_connman.get()))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight; ++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex()); blockHashes.push_back(pblock->GetHash().GetHex());
@ -457,7 +457,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (strMode != "template") if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
if (vNodes.empty()) if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!"); throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
if (IsInitialBlockDownload()) if (IsInitialBlockDownload())
@ -754,7 +757,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
CValidationState state; CValidationState state;
submitblock_StateCatcher sc(block.GetHash()); submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc); RegisterValidationInterface(&sc);
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, g_connman.get());
UnregisterValidationInterface(&sc); UnregisterValidationInterface(&sc);
if (fBlockPresent) if (fBlockPresent)
{ {

11
src/rpc/misc.cpp

@ -89,7 +89,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
#endif #endif
obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size())); if(g_connman)
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
@ -471,14 +472,16 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
// atomically with the time change to prevent peers from being // atomically with the time change to prevent peers from being
// disconnected because we think we haven't communicated with them // disconnected because we think we haven't communicated with them
// in a long time. // in a long time.
LOCK2(cs_main, cs_vNodes); LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64()); SetMockTime(params[0].get_int64());
uint64_t t = GetTime(); uint64_t t = GetTime();
BOOST_FOREACH(CNode* pnode, vNodes) { if(g_connman) {
pnode->nLastSend = pnode->nLastRecv = t; g_connman->ForEachNode([t](CNode* pnode) {
pnode->nLastSend = pnode->nLastRecv = t;
});
} }
return NullUniValue; return NullUniValue;

108
src/rpc/net.cpp

@ -36,9 +36,10 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "")
); );
LOCK2(cs_main, cs_vNodes); if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
return (int)vNodes.size(); return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
} }
UniValue ping(const UniValue& params, bool fHelp) UniValue ping(const UniValue& params, bool fHelp)
@ -54,29 +55,16 @@ UniValue ping(const UniValue& params, bool fHelp)
+ HelpExampleRpc("ping", "") + HelpExampleRpc("ping", "")
); );
// Request that each node send a ping during next message processing pass if(!g_connman)
LOCK2(cs_main, cs_vNodes); throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
BOOST_FOREACH(CNode* pNode, vNodes) {
pNode->fPingQueued = true;
}
// Request that each node send a ping during next message processing pass
g_connman->ForEachNode([](CNode* pnode) {
pnode->fPingQueued = true;
});
return NullUniValue; return NullUniValue;
} }
static void CopyNodeStats(std::vector<CNodeStats>& vstats)
{
vstats.clear();
LOCK(cs_vNodes);
vstats.reserve(vNodes.size());
BOOST_FOREACH(CNode* pnode, vNodes) {
CNodeStats stats;
pnode->copyStats(stats);
vstats.push_back(stats);
}
}
UniValue getpeerinfo(const UniValue& params, bool fHelp) UniValue getpeerinfo(const UniValue& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
@ -127,10 +115,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "")
); );
LOCK(cs_main); if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
vector<CNodeStats> vstats; vector<CNodeStats> vstats;
CopyNodeStats(vstats); g_connman->GetNodeStats(vstats);
UniValue ret(UniValue::VARR); UniValue ret(UniValue::VARR);
@ -214,32 +203,27 @@ UniValue addnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
); );
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
string strNode = params[0].get_str(); string strNode = params[0].get_str();
if (strCommand == "onetry") if (strCommand == "onetry")
{ {
CAddress addr; CAddress addr;
OpenNetworkConnection(addr, false, NULL, strNode.c_str()); g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
return NullUniValue; return NullUniValue;
} }
LOCK(cs_vAddedNodes);
vector<string>::iterator it = vAddedNodes.begin();
for(; it != vAddedNodes.end(); it++)
if (strNode == *it)
break;
if (strCommand == "add") if (strCommand == "add")
{ {
if (it != vAddedNodes.end()) if(!g_connman->AddNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
vAddedNodes.push_back(strNode);
} }
else if(strCommand == "remove") else if(strCommand == "remove")
{ {
if (it == vAddedNodes.end()) if(!g_connman->RemoveAddedNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
vAddedNodes.erase(it);
} }
return NullUniValue; return NullUniValue;
@ -258,11 +242,12 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
); );
CNode* pNode = FindNode(params[0].get_str()); if(!g_connman)
if (pNode == NULL) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
pNode->fDisconnect = true; bool ret = g_connman->DisconnectNode(params[0].get_str());
if (!ret)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
return NullUniValue; return NullUniValue;
} }
@ -296,7 +281,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"") + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
); );
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo(); if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
if (params.size() == 1) { if (params.size() == 1) {
bool found = false; bool found = false;
@ -358,19 +346,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
+ HelpExampleCli("getnettotals", "") + HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "") + HelpExampleRpc("getnettotals", "")
); );
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis())); obj.push_back(Pair("timemillis", GetTimeMillis()));
UniValue outboundLimit(UniValue::VOBJ); UniValue outboundLimit(UniValue::VOBJ);
outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe())); outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe()));
outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget())); outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget()));
outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false))); outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false)));
outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true))); outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true)));
outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft())); outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft()));
outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle())); outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle()));
obj.push_back(Pair("uploadtarget", outboundLimit)); obj.push_back(Pair("uploadtarget", outboundLimit));
return obj; return obj;
} }
@ -437,15 +427,16 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
); );
LOCK(cs_main); LOCK(cs_main);
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion", strSubVersion)); obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); if(g_connman)
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
obj.push_back(Pair("localrelay", fRelayTxes)); obj.push_back(Pair("localrelay", fRelayTxes));
obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size())); if(g_connman)
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
UniValue localAddresses(UniValue::VARR); UniValue localAddresses(UniValue::VARR);
@ -485,6 +476,8 @@ UniValue setban(const UniValue& params, bool fHelp)
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
); );
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CSubNet subNet; CSubNet subNet;
CNetAddr netAddr; CNetAddr netAddr;
@ -506,7 +499,7 @@ UniValue setban(const UniValue& params, bool fHelp)
if (strCommand == "add") if (strCommand == "add")
{ {
if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr)) if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified int64_t banTime = 0; //use standard bantime if not specified
@ -517,11 +510,11 @@ UniValue setban(const UniValue& params, bool fHelp)
if (params.size() == 4 && params[3].isTrue()) if (params.size() == 4 && params[3].isTrue())
absolute = true; absolute = true;
isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
} }
else if(strCommand == "remove") else if(strCommand == "remove")
{ {
if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) )) if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
} }
return NullUniValue; return NullUniValue;
@ -538,8 +531,11 @@ UniValue listbanned(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listbanned", "") + HelpExampleRpc("listbanned", "")
); );
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
banmap_t banMap; banmap_t banMap;
CNode::GetBanned(banMap); g_connman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR); UniValue bannedAddresses(UniValue::VARR);
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
@ -567,8 +563,10 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
+ HelpExampleCli("clearbanned", "") + HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "") + HelpExampleRpc("clearbanned", "")
); );
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CNode::ClearBanned(); g_connman->ClearBanned();
return NullUniValue; return NullUniValue;
} }

1
src/rpc/protocol.h

@ -63,6 +63,7 @@ enum RPCErrorCode
RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
//! Wallet errors //! Wallet errors
RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.) RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)

8
src/rpc/rawtransaction.cpp

@ -891,8 +891,14 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) { } else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
} }
RelayTransaction(tx); if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CInv inv(MSG_TX, hashTx);
g_connman->ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
return hashTx.GetHex(); return hashTx.GetHex();
} }

56
src/test/DoS_tests.cpp

@ -40,69 +40,75 @@ CService ip(uint32_t i)
return CService(CNetAddr(s), Params().GetDefaultPort()); return CService(CNetAddr(s), Params().GetDefaultPort());
} }
static NodeId id = 0;
BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_AUTO_TEST_CASE(DoS_banning)
{ {
CNode::ClearBanned(); connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE); CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(INVALID_SOCKET, addr1, "", true); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true);
GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
dummyNode1.nVersion = 1; dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned Misbehaving(dummyNode1.GetId(), 100); // Should get banned
SendMessages(&dummyNode1); SendMessages(&dummyNode1, *connman);
BOOST_CHECK(CNode::IsBanned(addr1)); BOOST_CHECK(connman->IsBanned(addr1));
BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE); CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(INVALID_SOCKET, addr2, "", true); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, "", true);
GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2);
dummyNode2.nVersion = 1; dummyNode2.nVersion = 1;
Misbehaving(dummyNode2.GetId(), 50); Misbehaving(dummyNode2.GetId(), 50);
SendMessages(&dummyNode2); SendMessages(&dummyNode2, *connman);
BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
Misbehaving(dummyNode2.GetId(), 50); Misbehaving(dummyNode2.GetId(), 50);
SendMessages(&dummyNode2); SendMessages(&dummyNode2, *connman);
BOOST_CHECK(CNode::IsBanned(addr2)); BOOST_CHECK(connman->IsBanned(addr2));
} }
BOOST_AUTO_TEST_CASE(DoS_banscore) BOOST_AUTO_TEST_CASE(DoS_banscore)
{ {
CNode::ClearBanned(); connman->ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE); CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(INVALID_SOCKET, addr1, "", true); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true);
GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
dummyNode1.nVersion = 1; dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); Misbehaving(dummyNode1.GetId(), 100);
SendMessages(&dummyNode1); SendMessages(&dummyNode1, *connman);
BOOST_CHECK(!CNode::IsBanned(addr1)); BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 10); Misbehaving(dummyNode1.GetId(), 10);
SendMessages(&dummyNode1); SendMessages(&dummyNode1, *connman);
BOOST_CHECK(!CNode::IsBanned(addr1)); BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 1); Misbehaving(dummyNode1.GetId(), 1);
SendMessages(&dummyNode1); SendMessages(&dummyNode1, *connman);
BOOST_CHECK(CNode::IsBanned(addr1)); BOOST_CHECK(connman->IsBanned(addr1));
mapArgs.erase("-banscore"); mapArgs.erase("-banscore");
} }
BOOST_AUTO_TEST_CASE(DoS_bantime) BOOST_AUTO_TEST_CASE(DoS_bantime)
{ {
CNode::ClearBanned(); connman->ClearBanned();
int64_t nStartTime = GetTime(); int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime() SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE); CAddress addr(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode(INVALID_SOCKET, addr, "", true); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, "", true);
GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode);
dummyNode.nVersion = 1; dummyNode.nVersion = 1;
Misbehaving(dummyNode.GetId(), 100); Misbehaving(dummyNode.GetId(), 100);
SendMessages(&dummyNode); SendMessages(&dummyNode, *connman);
BOOST_CHECK(CNode::IsBanned(addr)); BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60); SetMockTime(nStartTime+60*60);
BOOST_CHECK(CNode::IsBanned(addr)); BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1); SetMockTime(nStartTime+60*60*24+1);
BOOST_CHECK(!CNode::IsBanned(addr)); BOOST_CHECK(!connman->IsBanned(addr));
} }
CTransaction RandomOrphan() CTransaction RandomOrphan()

2
src/test/miner_tests.cpp

@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce; pblock->nNonce = blockinfo[i].nonce;
CValidationState state; CValidationState state;
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, connman));
BOOST_CHECK(state.IsValid()); BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash(); pblock->hashPrevBlock = pblock->GetHash();
} }

6
src/test/net_tests.cpp

@ -153,6 +153,8 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_AUTO_TEST_CASE(cnode_simple_test) BOOST_AUTO_TEST_CASE(cnode_simple_test)
{ {
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
NodeId id = 0;
int height = 0;
in_addr ipv4Addr; in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001; ipv4Addr.s_addr = 0xa0b0c001;
@ -162,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
bool fInboundIn = false; bool fInboundIn = false;
// Test that fFeeler is false by default. // Test that fFeeler is false by default.
CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn); CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false); BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true; fInboundIn = true;
CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn); CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false); BOOST_CHECK(pnode2->fFeeler == false);
} }

8
src/test/test_bitcoin.cpp

@ -26,6 +26,8 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
std::unique_ptr<CConnman> g_connman;
extern bool fPrintToConsole; extern bool fPrintToConsole;
extern void noui_connect(); extern void noui_connect();
@ -43,6 +45,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup() BasicTestingSetup::~BasicTestingSetup()
{ {
ECC_Stop(); ECC_Stop();
g_connman.reset();
} }
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
@ -50,6 +53,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
// Ideally we'd move all the RPC tests to the functional testing framework // Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here. // instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC); RegisterAllCoreRPCCommands(tableRPC);
ClearDatadirCache(); ClearDatadirCache();
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
@ -68,6 +72,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
nScriptCheckThreads = 3; nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++) for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck); threadGroup.create_thread(&ThreadScriptCheck);
g_connman = std::unique_ptr<CConnman>(new CConnman());
connman = g_connman.get();
RegisterNodeSignals(GetNodeSignals()); RegisterNodeSignals(GetNodeSignals());
} }
@ -118,7 +124,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
CValidationState state; CValidationState state;
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, connman);
CBlock result = block; CBlock result = block;
delete pblocktemplate; delete pblocktemplate;

2
src/test/test_bitcoin.h

@ -27,10 +27,12 @@ struct BasicTestingSetup {
/** Testing setup that configures a complete environment. /** Testing setup that configures a complete environment.
* Included are data directory, coins database, script check threads setup. * Included are data directory, coins database, script check threads setup.
*/ */
class CConnman;
struct TestingSetup: public BasicTestingSetup { struct TestingSetup: public BasicTestingSetup {
CCoinsViewDB *pcoinsdbview; CCoinsViewDB *pcoinsdbview;
boost::filesystem::path pathTemp; boost::filesystem::path pathTemp;
boost::thread_group threadGroup; boost::thread_group threadGroup;
CConnman* connman;
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN); TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup(); ~TestingSetup();

4
src/validationinterface.cpp

@ -18,7 +18,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
@ -28,7 +28,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));

5
src/validationinterface.h

@ -13,6 +13,7 @@ class CBlock;
class CBlockIndex; class CBlockIndex;
struct CBlockLocator; struct CBlockLocator;
class CBlockIndex; class CBlockIndex;
class CConnman;
class CReserveScript; class CReserveScript;
class CTransaction; class CTransaction;
class CValidationInterface; class CValidationInterface;
@ -37,7 +38,7 @@ protected:
virtual void SetBestChain(const CBlockLocator &locator) {} virtual void SetBestChain(const CBlockLocator &locator) {}
virtual void UpdatedTransaction(const uint256 &hash) {} virtual void UpdatedTransaction(const uint256 &hash) {}
virtual void Inventory(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {}
virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
virtual void BlockChecked(const CBlock&, const CValidationState&) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {}
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {}; virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
virtual void ResetRequestCount(const uint256 &hash) {}; virtual void ResetRequestCount(const uint256 &hash) {};
@ -58,7 +59,7 @@ struct CMainSignals {
/** Notifies listeners about an inventory item being seen on the network. */ /** Notifies listeners about an inventory item being seen on the network. */
boost::signals2::signal<void (const uint256 &)> Inventory; boost::signals2::signal<void (const uint256 &)> Inventory;
/** Tells listeners to broadcast their data. */ /** Tells listeners to broadcast their data. */
boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast; boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
/** Notifies listeners of a block validation result */ /** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
/** Notifies listeners that a key for mining is required (coinbase) */ /** Notifies listeners that a key for mining is required (coinbase) */

15
src/wallet/rpcwallet.cpp

@ -346,6 +346,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
if (nValue > curBalance) if (nValue > curBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
if (pwalletMain->GetBroadcastTransactions() && !g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
// Parse Bitcoin address // Parse Bitcoin address
CScript scriptPubKey = GetScriptForDestination(address); CScript scriptPubKey = GetScriptForDestination(address);
@ -362,7 +365,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
} }
if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get()))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here.");
} }
@ -891,6 +894,9 @@ UniValue sendmany(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
if (pwalletMain->GetBroadcastTransactions() && !g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
UniValue sendTo = params[1].get_obj(); UniValue sendTo = params[1].get_obj();
int nMinDepth = 1; int nMinDepth = 1;
@ -953,7 +959,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason); bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
if (!fCreated) if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
if (!pwalletMain->CommitTransaction(wtx, keyChange)) if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get()))
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
return wtx.GetHash().GetHex(); return wtx.GetHash().GetHex();
@ -2308,9 +2314,12 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
"Returns array of transaction ids that were re-broadcast.\n" "Returns array of transaction ids that were re-broadcast.\n"
); );
if (!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime()); std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
UniValue result(UniValue::VARR); UniValue result(UniValue::VARR);
BOOST_FOREACH(const uint256& txid, txids) BOOST_FOREACH(const uint256& txid, txids)
{ {

24
src/wallet/wallet.cpp

@ -1453,15 +1453,21 @@ void CWallet::ReacceptWalletTransactions()
} }
} }
bool CWalletTx::RelayWalletTransaction() bool CWalletTx::RelayWalletTransaction(CConnman* connman)
{ {
assert(pwallet->GetBroadcastTransactions()); assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase()) if (!IsCoinBase())
{ {
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString()); LogPrintf("Relaying wtx %s\n", GetHash().ToString());
RelayTransaction((CTransaction)*this); if (connman) {
return true; CInv inv(MSG_TX, GetHash());
connman->ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
return true;
}
} }
} }
return false; return false;
@ -1688,7 +1694,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
return CTransaction(tx1) == CTransaction(tx2); return CTransaction(tx1) == CTransaction(tx2);
} }
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime) std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)
{ {
std::vector<uint256> result; std::vector<uint256> result;
@ -1706,13 +1712,13 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{ {
CWalletTx& wtx = *item.second; CWalletTx& wtx = *item.second;
if (wtx.RelayWalletTransaction()) if (wtx.RelayWalletTransaction(connman))
result.push_back(wtx.GetHash()); result.push_back(wtx.GetHash());
} }
return result; return result;
} }
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime) void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
{ {
// Do this infrequently and randomly to avoid giving away // Do this infrequently and randomly to avoid giving away
// that these are our transactions. // that these are our transactions.
@ -1730,7 +1736,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
// Rebroadcast unconfirmed txes older than 5 minutes before the last // Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found: // block was found:
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60); std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
if (!relayed.empty()) if (!relayed.empty())
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size()); LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
} }
@ -2447,7 +2453,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
/** /**
* Call after CreateTransaction unless you want to abort * Call after CreateTransaction unless you want to abort
*/ */
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman)
{ {
{ {
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
@ -2481,7 +2487,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false; return false;
} }
wtxNew.RelayWalletTransaction(); wtxNew.RelayWalletTransaction(connman);
} }
} }
return true; return true;

8
src/wallet/wallet.h

@ -401,7 +401,7 @@ public:
int64_t GetTxTime() const; int64_t GetTxTime() const;
int GetRequestCount() const; int GetRequestCount() const;
bool RelayWalletTransaction(); bool RelayWalletTransaction(CConnman* connman);
std::set<uint256> GetConflicts() const; std::set<uint256> GetConflicts() const;
}; };
@ -748,8 +748,8 @@ public:
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions(); void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime); void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman);
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime); std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
CAmount GetBalance() const; CAmount GetBalance() const;
CAmount GetUnconfirmedBalance() const; CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const; CAmount GetImmatureBalance() const;
@ -770,7 +770,7 @@ public:
*/ */
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true); std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman);
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);

Loading…
Cancel
Save