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)
This commit is contained in:
Wladimir J. van der Laan 2016-09-09 11:43:13 +02:00
commit 6423116741
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
32 changed files with 1383 additions and 905 deletions

View file

@ -71,6 +71,7 @@ endif
.PHONY: FORCE check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
base58.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_SOURCES = \
addrman.cpp \
addrdb.cpp \
bloom.cpp \
blockencodings.cpp \
chain.cpp \

218
src/addrdb.cpp Normal file
View file

@ -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 Normal file
View file

@ -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

View file

@ -42,6 +42,7 @@
#endif
#include <stdint.h>
#include <stdio.h>
#include <memory>
#ifndef WIN32
#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_STOPAFTERBLOCKIMPORT = false;
std::unique_ptr<CConnman> g_connman;
#if ENABLE_ZMQ
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
@ -197,7 +199,10 @@ void Shutdown()
if (pwalletMain)
pwalletMain->Flush(false);
#endif
StopNode();
MapPort(false);
g_connman->Stop();
g_connman.reset();
StopTorControl();
UnregisterNodeSignals(GetNodeSignals());
@ -269,11 +274,11 @@ void HandleSIGHUP(int)
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))
return false;
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)
return InitError(strError);
return false;
@ -864,7 +869,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
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
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):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
ServiceFlags nLocalServices = NODE_NETWORK;
ServiceFlags nRelevantServices = NODE_NETWORK;
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
@ -1108,6 +1116,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#endif // ENABLE_WALLET
// ********************************************************* Step 6: network initialization
assert(!g_connman);
g_connman = std::unique_ptr<CConnman>(new CConnman());
CConnman& connman = *g_connman;
RegisterNodeSignals(GetNodeSignals());
// 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);
if (!subnet.IsValid())
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;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
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"]) {
CService addrBind;
@ -1205,14 +1217,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError(ResolveErrMsg("whitebind", strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
}
}
else {
struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY;
fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE);
fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
}
if (!fBound)
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"])
AddOneShot(strDest);
connman.AddOneShot(strDest);
#if ENABLE_ZMQ
pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
@ -1239,7 +1251,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
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
@ -1505,7 +1517,25 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
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

View file

@ -325,12 +325,6 @@ CNodeState *State(NodeId pnode) {
return &it->second;
}
int GetHeight()
{
LOCK(cs_main);
return chainActive.Height();
}
void UpdatePreferredDownload(CNode* node, CNodeState* state)
{
nPreferredDownload -= state->fPreferredDownload;
@ -348,7 +342,8 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) {
state.address = pnode->addr;
}
void FinalizeNode(NodeId nodeid) {
void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
fUpdateConnectionTime = false;
LOCK(cs_main);
CNodeState *state = State(nodeid);
@ -356,7 +351,7 @@ void FinalizeNode(NodeId nodeid) {
nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
AddressCurrentlyConnected(state->address);
fUpdateConnectionTime = true;
}
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) {
if (nLocalServices & NODE_WITNESS) {
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) {
if (pfrom->GetLocalServices() & NODE_WITNESS) {
// Don't ever request compact blocks when segwit is enabled.
return;
}
@ -483,11 +478,12 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front());
if (pnodeStop) {
bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
return true;
});
if(found)
lNodesAnnouncingHeaderAndIDs.pop_front();
}
}
fAnnounceUsingCMPCTBLOCK = true;
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
@ -637,7 +633,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
void RegisterNodeSignals(CNodeSignals& nodeSignals)
{
nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages);
nodeSignals.InitializeNode.connect(&InitializeNode);
@ -646,7 +641,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals)
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{
nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages);
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
* 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 *pindexNewTip = NULL;
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).
// Notifications/callbacks that can run without cs_main
if(connman)
connman->SetBestHeight(nNewHeight);
// throw all transactions though the signal-interface
// while _not_ holding the cs_main lock
@ -3088,15 +3084,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
int nBlockEstimate = 0;
if (fCheckpointsEnabled)
nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
if(connman) {
connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) {
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
pnode->PushBlockHash(hash);
}
}
}
});
}
// Notify external listeners about the new tip.
if (!vHashes.empty()) {
@ -3731,7 +3726,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
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);
@ -3753,7 +3748,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
NotifyHeaderTip();
if (!ActivateBestChain(state, chainparams, pblock))
if (!ActivateBestChain(state, chainparams, pblock, connman))
return error("%s: ActivateBestChain failed", __func__);
return true;
@ -4725,9 +4720,47 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
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();
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
vector<CInv> vNotFound;
@ -4735,7 +4768,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
while (it != pfrom->vRecvGetData.end()) {
// Don't bother if send buffer is too full to respond anyway
if (pfrom->nSendSize >= SendBufferSize())
if (pfrom->nSendSize >= nMaxSendBufferSize)
break;
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
// never disconnect whitelisted nodes
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());
@ -4891,8 +4924,10 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params
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);
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::FILTERADD ||
strCommand == NetMsgType::FILTERCLEAR))
@ -4943,7 +4978,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->nServices = ServiceFlags(nServiceInt);
if (!pfrom->fInbound)
{
addrman.SetServices(pfrom->addr, pfrom->nServices);
connman.SetServices(pfrom->addr, 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
if (nNonce == nLocalHostNonce && nNonce > 1)
if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true;
@ -5024,7 +5059,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Advertise our address
if (fListen && !IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr);
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
if (addr.IsRoutable())
{
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
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->fGetAddr = true;
}
addrman.Good(pfrom->addr);
connman.MarkAddressGood(pfrom->addr);
}
pfrom->fSuccessfullyConnected = true;
@ -5107,7 +5142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> vAddr;
// 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;
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())
{
// Relay to a limited number of other nodes
{
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);
}
RelayAddress(addr, fReachable, connman);
}
// Do not store addresses outside our network
if (fReachable)
vAddrOk.push_back(addr);
}
addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
@ -5238,7 +5254,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
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));
else
vToFetch.push_back(inv);
@ -5261,7 +5277,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Track requests for our stuff
GetMainSignals().Inventory(inv.hash);
if (pfrom->nSendSize > (SendBufferSize() * 2)) {
if (pfrom->nSendSize > (nMaxSendBufferSize * 2)) {
Misbehaving(pfrom->GetId(), 50);
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);
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)) {
mempool.check(pcoinsTip);
RelayTransaction(tx);
RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i);
}
@ -5484,7 +5500,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
continue;
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx);
RelayTransaction(orphanTx, connman);
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
vWorkQueue.emplace_back(orphanHash, i);
}
@ -5565,7 +5581,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
RelayTransaction(tx);
RelayTransaction(tx, connman);
} else {
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();
CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
blockTxnMsg << txn;
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams);
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
} else {
req.blockhash = pindex->GetBlockHash();
pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req);
@ -5705,7 +5721,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
headers.push_back(cmpctblock.header);
CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
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);
} else {
CValidationState state;
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, &connman);
int nDoS;
if (state.IsInvalid(nDoS)) {
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);
}
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
// 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
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
// conditions in AcceptBlock().
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman);
int nDoS;
if (state.IsInvalid(nDoS)) {
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->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
vector<CAddress> vAddr = connman.GetAddresses();
BOOST_FOREACH(const CAddress &addr, vAddr)
pfrom->PushAddress(addr);
}
@ -5961,14 +5977,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
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());
pfrom->fDisconnect = 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());
pfrom->fDisconnect = true;
@ -6167,9 +6183,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// requires LOCK(cs_vRecvMsg)
bool ProcessMessages(CNode* pfrom)
bool ProcessMessages(CNode* pfrom, CConnman& connman)
{
const CChainParams& chainparams = Params();
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
//if (fDebug)
// LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
@ -6184,7 +6201,7 @@ bool ProcessMessages(CNode* pfrom)
bool fOk = true;
if (!pfrom->vRecvGetData.empty())
ProcessGetData(pfrom, chainparams.GetConsensus());
ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
// this maintains the order of responses
if (!pfrom->vRecvGetData.empty()) return fOk;
@ -6192,7 +6209,7 @@ bool ProcessMessages(CNode* pfrom)
std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
// Don't bother if send buffer is too full to respond anyway
if (pfrom->nSendSize >= SendBufferSize())
if (pfrom->nSendSize >= nMaxSendBufferSize)
break;
// get next message
@ -6244,7 +6261,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams);
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman);
boost::this_thread::interruption_point();
}
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();
{
@ -6396,7 +6413,7 @@ bool SendMessages(CNode* pto)
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
else
{
CNode::Ban(pto->addr, BanReasonNodeMisbehaving);
connman.Ban(pto->addr, BanReasonNodeMisbehaving);
}
}
state.fShouldBan = false;
@ -6435,7 +6452,7 @@ bool SendMessages(CNode* pto)
// transactions become unconfirmed and spams other nodes.
if (!fReindex && !fImporting && !IsInitialBlockDownload())
{
GetMainSignals().Broadcast(nTimeBestReceived);
GetMainSignals().Broadcast(nTimeBestReceived, &connman);
}
//

View file

@ -34,6 +34,7 @@ class CBlockTreeDB;
class CBloomFilter;
class CChainParams;
class CInv;
class CConnman;
class CScriptCheck;
class CTxMemPool;
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.
* @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 */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@ -240,13 +241,14 @@ bool LoadBlockIndex();
/** Unload database information */
void UnloadBlockIndex();
/** 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.
*
* @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 */
void ThreadScriptCheck();
/** 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) */
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 */
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);
/**

File diff suppressed because it is too large Load diff

544
src/net.h
View file

@ -6,6 +6,8 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
#include "addrdb.h"
#include "addrman.h"
#include "amount.h"
#include "bloom.h"
#include "compat.h"
@ -20,6 +22,7 @@
#include <atomic>
#include <deque>
#include <stdint.h>
#include <memory>
#ifndef WIN32
#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;
/** Maximum length of strSubVer in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** Maximum number of outgoing nodes */
static const int MAX_OUTBOUND_CONNECTIONS = 8;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@ -79,25 +84,317 @@ static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
typedef int NodeId;
void AddOneShot(const std::string& strDest);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
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);
struct AddedNodeInfo
{
std::string strAddedNode;
CService resolvedAddress;
bool fConnected;
bool fInbound;
};
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);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
bool StopNode();
void SocketSendData(CNode *pnode);
size_t SocketSendData(CNode *pnode);
struct CombinerAll
{
@ -117,11 +414,10 @@ struct CombinerAll
// Signals for message handling
struct CNodeSignals
{
boost::signals2::signal<int ()> GetHeight;
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> ProcessMessages;
boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> SendMessages;
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 IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
extern bool fDiscover;
extern bool fListen;
extern ServiceFlags nLocalServices;
extern ServiceFlags nRelevantServices;
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 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 */
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 */
class CNode
{
@ -328,6 +548,7 @@ public:
CDataStream ssSend;
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
uint64_t nOptimisticBytesWritten;
uint64_t nSendBytes;
std::deque<CSerializeData> vSendMsg;
CCriticalSection cs_vSend;
@ -374,17 +595,6 @@ public:
const uint64_t nKeyedNetGroup;
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 mapRecvBytesPerMsgCmd;
@ -446,33 +656,28 @@ public:
CAmount lastSentFeeFilter;
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();
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&);
void operator=(const CNode&);
static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
uint64_t nLocalHostNonce;
ServiceFlags nLocalServices;
int nMyStartingHeight;
public:
NodeId GetId() const {
return id;
}
uint64_t GetLocalNonce() const {
return nLocalHostNonce;
}
int GetRefCount()
{
assert(nRefCount >= 0);
@ -489,7 +694,7 @@ public:
}
// 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)
void SetRecvVersion(int nVersionIn)
@ -749,110 +954,19 @@ public:
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);
static bool IsWhitelistedRange(const CNetAddr &ip);
static void AddWhitelistedRange(const CSubNet &subnet);
// Network stats
static void RecordBytesRecv(uint64_t bytes);
static void RecordBytesSent(uint64_t bytes);
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();
ServiceFlags GetLocalServices() const
{
return nLocalServices;
}
};
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. */
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

View file

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

View file

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

View file

@ -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())
return QString();
return QVariant();
QModelIndexList selection = view->selectionModel()->selectedRows(column);
if(!selection.isEmpty()) {
// 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,

View file

@ -70,7 +70,7 @@ namespace GUIUtil
@param[in] role Data role to extract from the model
@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);

View file

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

View file

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

View file

@ -876,37 +876,34 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point)
void RPCConsole::disconnectSelectedNode()
{
if(!g_connman)
return;
// 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
if (CNode *bannedNode = FindNode(strNode.toStdString())) {
bannedNode->fDisconnect = true;
if(g_connman->DisconnectNode(id))
clearSelectedNode();
}
}
void RPCConsole::banSelectedNode(int bantime)
{
if (!clientModel)
if (!clientModel || !g_connman)
return;
// 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
if (FindNode(strNode.toStdString())) {
std::string nStr = strNode.toStdString();
std::string addr;
int port = 0;
SplitHostPort(nStr, port, addr);
std::string nStr = strNode.toStdString();
std::string addr;
int port = 0;
SplitHostPort(nStr, port, addr);
CNetAddr resolved;
if(!LookupHost(addr.c_str(), resolved, false))
return;
CNode::Ban(resolved, BanReasonManuallyAdded, bantime);
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
}
CNetAddr resolved;
if(!LookupHost(addr.c_str(), resolved, false))
return;
g_connman->Ban(resolved, BanReasonManuallyAdded, bantime);
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
}
void RPCConsole::unbanSelectedNode()
@ -915,13 +912,13 @@ void RPCConsole::unbanSelectedNode()
return;
// 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;
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
if (possibleSubnet.IsValid())
if (possibleSubnet.IsValid() && g_connman)
{
CNode::Unban(possibleSubnet);
g_connman->Unban(possibleSubnet);
clientModel->getBanTableModel()->refresh();
}
}

View file

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

View file

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

View file

@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
continue;
}
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");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@ -457,7 +457,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (strMode != "template")
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!");
if (IsInitialBlockDownload())
@ -754,7 +757,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
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);
if (fBlockPresent)
{

View file

@ -89,7 +89,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
#endif
obj.push_back(Pair("blocks", (int)chainActive.Height()));
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("difficulty", (double)GetDifficulty()));
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
// disconnected because we think we haven't communicated with them
// in a long time.
LOCK2(cs_main, cs_vNodes);
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64());
uint64_t t = GetTime();
BOOST_FOREACH(CNode* pnode, vNodes) {
pnode->nLastSend = pnode->nLastRecv = t;
if(g_connman) {
g_connman->ForEachNode([t](CNode* pnode) {
pnode->nLastSend = pnode->nLastRecv = t;
});
}
return NullUniValue;

View file

@ -36,9 +36,10 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp)
+ 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)
@ -54,29 +55,16 @@ UniValue ping(const UniValue& params, bool fHelp)
+ HelpExampleRpc("ping", "")
);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
// Request that each node send a ping during next message processing pass
LOCK2(cs_main, cs_vNodes);
BOOST_FOREACH(CNode* pNode, vNodes) {
pNode->fPingQueued = true;
}
g_connman->ForEachNode([](CNode* pnode) {
pnode->fPingQueued = true;
});
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)
{
if (fHelp || params.size() != 0)
@ -127,10 +115,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
+ 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;
CopyNodeStats(vstats);
g_connman->GetNodeStats(vstats);
UniValue ret(UniValue::VARR);
@ -214,32 +203,27 @@ UniValue addnode(const UniValue& params, bool fHelp)
+ 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();
if (strCommand == "onetry")
{
CAddress addr;
OpenNetworkConnection(addr, false, NULL, strNode.c_str());
g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
return NullUniValue;
}
LOCK(cs_vAddedNodes);
vector<string>::iterator it = vAddedNodes.begin();
for(; it != vAddedNodes.end(); it++)
if (strNode == *it)
break;
if (strCommand == "add")
{
if (it != vAddedNodes.end())
if(!g_connman->AddNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
vAddedNodes.push_back(strNode);
}
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.");
vAddedNodes.erase(it);
}
return NullUniValue;
@ -258,11 +242,12 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
);
CNode* pNode = FindNode(params[0].get_str());
if (pNode == NULL)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
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;
}
@ -296,7 +281,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
+ 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) {
bool found = false;
@ -358,19 +346,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
+ HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
UniValue outboundLimit(UniValue::VOBJ);
outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe()));
outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget()));
outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false)));
outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true)));
outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft()));
outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle()));
outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe()));
outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget()));
outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false)));
outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true)));
outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft()));
outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle()));
obj.push_back(Pair("uploadtarget", outboundLimit));
return obj;
}
@ -437,15 +427,16 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion", strSubVersion));
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("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("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
UniValue localAddresses(UniValue::VARR);
@ -485,6 +476,8 @@ UniValue setban(const UniValue& params, bool fHelp)
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ 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;
CNetAddr netAddr;
@ -506,7 +499,7 @@ UniValue setban(const UniValue& params, bool fHelp)
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");
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())
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")
{
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");
}
return NullUniValue;
@ -538,8 +531,11 @@ UniValue listbanned(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listbanned", "")
);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
banmap_t banMap;
CNode::GetBanned(banMap);
g_connman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
@ -567,8 +563,10 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
+ HelpExampleCli("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;
}

View file

@ -63,6 +63,7 @@ enum RPCErrorCode
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_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
//! Wallet errors
RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)

View file

@ -891,8 +891,14 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
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();
}

View file

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

View file

@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
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());
pblock->hashPrevBlock = pblock->GetHash();
}

View file

@ -153,6 +153,8 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
SOCKET hSocket = INVALID_SOCKET;
NodeId id = 0;
int height = 0;
in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;
@ -162,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
bool fInboundIn = false;
// 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->fFeeler == false);
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->fFeeler == false);
}

View file

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

View file

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

View file

@ -18,7 +18,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, 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.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, 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.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
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.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));

View file

@ -13,6 +13,7 @@ class CBlock;
class CBlockIndex;
struct CBlockLocator;
class CBlockIndex;
class CConnman;
class CReserveScript;
class CTransaction;
class CValidationInterface;
@ -37,7 +38,7 @@ protected:
virtual void SetBestChain(const CBlockLocator &locator) {}
virtual void UpdatedTransaction(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 GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
virtual void ResetRequestCount(const uint256 &hash) {};
@ -58,7 +59,7 @@ struct CMainSignals {
/** Notifies listeners about an inventory item being seen on the network. */
boost::signals2::signal<void (const uint256 &)> Inventory;
/** 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 */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
/** Notifies listeners that a key for mining is required (coinbase) */

View file

@ -346,6 +346,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
if (nValue > curBalance)
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
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));
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.");
}
@ -891,6 +894,9 @@ UniValue sendmany(const UniValue& params, bool fHelp)
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]);
UniValue sendTo = params[1].get_obj();
int nMinDepth = 1;
@ -953,7 +959,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
if (!fCreated)
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");
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"
);
if (!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
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);
BOOST_FOREACH(const uint256& txid, txids)
{

View file

@ -1453,15 +1453,21 @@ void CWallet::ReacceptWalletTransactions()
}
}
bool CWalletTx::RelayWalletTransaction()
bool CWalletTx::RelayWalletTransaction(CConnman* connman)
{
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
{
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
RelayTransaction((CTransaction)*this);
return true;
if (connman) {
CInv inv(MSG_TX, GetHash());
connman->ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
return true;
}
}
}
return false;
@ -1688,7 +1694,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
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;
@ -1706,13 +1712,13 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *item.second;
if (wtx.RelayWalletTransaction())
if (wtx.RelayWalletTransaction(connman))
result.push_back(wtx.GetHash());
}
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
// 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
// block was found:
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
if (!relayed.empty())
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
*/
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman)
{
{
LOCK2(cs_main, cs_wallet);
@ -2481,7 +2487,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
}
wtxNew.RelayWalletTransaction();
wtxNew.RelayWalletTransaction(connman);
}
}
return true;

View file

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