Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)

* net: move CBanDB and CAddrDB out of net.h/cpp

This will eventually solve a circular dependency

* net: Create CConnman to encapsulate p2p connections

* net: Move socket binding into CConnman

* net: move OpenNetworkConnection into CConnman

* net: move ban and addrman functions into CConnman

* net: Add oneshot functions to CConnman

* net: move added node functions to CConnman

* net: Add most functions needed for vNodes to CConnman

* net: handle nodesignals in CConnman

* net: Pass CConnection to wallet rather than using the global

* net: Add rpc error for missing/disabled p2p functionality

* net: Pass CConnman around as needed

* gui: add NodeID to the peer table

* net: create generic functor accessors and move vNodes to CConnman

* net: move whitelist functions into CConnman

* net: move nLastNodeId to CConnman

* net: move nLocalHostNonce to CConnman

This behavior seems to have been quite racy and broken.

Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.

* net: move messageHandlerCondition to CConnman

* net: move send/recv statistics to CConnman

* net: move SendBufferSize/ReceiveFloodSize to CConnman

* net: move nLocalServices/nRelevantServices to CConnman

These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).

* net: move semOutbound and semMasternodeOutbound to CConnman

* net: SocketSendData returns written size

* net: move max/max-outbound to CConnman

* net: Pass best block known height into CConnman

CConnman then passes the current best height into CNode at creation time.

This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.

This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.

This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.

* net: pass CClientUIInterface into CConnman

* net: Drop StartNode/StopNode and use CConnman directly

* net: Introduce CConnection::Options to avoid passing so many params

* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options

* net: move vNodesDisconnected into CConnman

* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting

* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead

* net: move MAX_FEELER_CONNECTIONS into connman
This commit is contained in:
Oleg Girko 2017-07-21 10:35:19 +01:00 committed by UdjinM6
parent 15958c594c
commit a9d771e497
54 changed files with 1567 additions and 1070 deletions

View File

@ -70,6 +70,7 @@ endif
.PHONY: FORCE check-symbols check-security
# dash core #
BITCOIN_CORE_H = \
addrdb.h \
activemasternode.h \
addressindex.h \
spentindex.h \
@ -207,6 +208,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 \
alert.cpp \
bloom.cpp \
chain.cpp \

View File

@ -151,27 +151,23 @@ void CActiveMasternode::ManageStateInitial()
return;
}
bool fFoundLocal = false;
{
LOCK(cs_vNodes);
// First try to find whatever local address is specified by externalip option
fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
if(!fFoundLocal) {
// nothing and no live connections, can't do anything for now
if (vNodes.empty()) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
return;
}
// We have some peers, let's try to find our local address from one of them
BOOST_FOREACH(CNode* pnode, vNodes) {
if (pnode->fSuccessfullyConnected && pnode->addr.IsIPv4()) {
fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
if(fFoundLocal) break;
}
}
// First try to find whatever local address is specified by externalip option
bool fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
if(!fFoundLocal) {
bool empty = true;
// If we have some peers, let's try to find our local address from one of them
g_connman->ForEachNodeContinueIf([&fFoundLocal, &empty, this](CNode* pnode) {
empty = false;
if (pnode->fSuccessfullyConnected && pnode->addr.IsIPv4())
fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
return !fFoundLocal;
});
// nothing and no live connections, can't do anything for now
if (empty) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
return;
}
}
@ -199,7 +195,8 @@ void CActiveMasternode::ManageStateInitial()
LogPrintf("CActiveMasternode::ManageStateInitial -- Checking inbound connection to '%s'\n", service.ToString());
if(!ConnectNode(CAddress(service, NODE_NETWORK), NULL, true)) {
// TODO: Pass CConnman instance somehow and don't use global variable.
if(!g_connman->ConnectNode(CAddress(service, NODE_NETWORK), NULL, true)) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = "Could not connect to " + service.ToString();
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);

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

@ -103,7 +103,8 @@ void CDarkSendRelay::RelayThroughNode(int nRank)
if(pmn != NULL){
//printf("RelayThroughNode %s\n", pmn->addr.ToString().c_str());
CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL);
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = g_connman->ConnectNode((CAddress)pmn->addr, NULL);
if(pnode) {
//printf("Connected\n");
pnode->PushMessage("dsr", (*this));

View File

@ -678,7 +678,7 @@ bool CGovernanceObject::GetCurrentMNVotes(const CTxIn& mnCollateralOutpoint, vot
void CGovernanceObject::Relay()
{
CInv inv(MSG_GOVERNANCE_OBJECT, GetHash());
RelayInv(inv, PROTOCOL_VERSION);
g_connman->RelayInv(inv, PROTOCOL_VERSION);
}
void CGovernanceObject::UpdateSentinelVariables()

View File

@ -226,7 +226,7 @@ CGovernanceVote::CGovernanceVote(CTxIn vinMasternodeIn, uint256 nParentHashIn, v
void CGovernanceVote::Relay() const
{
CInv inv(MSG_GOVERNANCE_OBJECT_VOTE, GetHash());
RelayInv(inv, PROTOCOL_VERSION);
g_connman->RelayInv(inv, PROTOCOL_VERSION);
}
bool CGovernanceVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)

View File

@ -1421,7 +1421,7 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex)
void CGovernanceManager::RequestOrphanObjects()
{
std::vector<CNode*> vNodesCopy = CopyNodeVector();
std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector();
std::vector<uint256> vecHashesFiltered;
{
@ -1448,7 +1448,7 @@ void CGovernanceManager::RequestOrphanObjects()
}
}
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
}
void CGovernanceManager::CleanOrphanObjects()

View File

@ -63,6 +63,7 @@
#include <stdint.h>
#include <stdio.h>
#include <memory>
#ifndef WIN32
#include <signal.h>
@ -85,7 +86,7 @@
using namespace std;
extern void ThreadSendAlert();
extern void ThreadSendAlert(CConnman& connman);
#ifdef ENABLE_WALLET
CWallet* pwalletMain = NULL;
@ -97,6 +98,8 @@ 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;
#endif
@ -223,8 +226,10 @@ void PrepareShutdown()
if (pwalletMain)
pwalletMain->Flush(false);
#endif
GenerateBitcoins(false, 0, Params());
StopNode();
GenerateBitcoins(false, 0, Params(), *g_connman);
MapPort(false);
g_connman->Stop();
g_connman.reset();
// STORE DATA CACHES INTO SERIALIZED DAT FILES
CFlatDB<CMasternodeMan> flatdb1("mncache.dat", "magicMasternodeCache");
@ -343,11 +348,11 @@ bool static InitWarning(const std::string &str)
return 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;
@ -1004,7 +1009,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);
@ -1169,6 +1174,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", true))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
@ -1305,6 +1313,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
@ -1341,7 +1353,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CSubNet subnet(net);
if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
CNode::AddWhitelistedRange(subnet);
connman.AddWhitelistedRange(subnet);
}
}
@ -1390,7 +1402,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
CService addrBind;
@ -1398,14 +1410,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
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."));
@ -1421,7 +1433,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);
@ -1435,7 +1447,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterValidationInterface(pdsNotificationInterface);
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
@ -1956,7 +1968,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (fMasterNode)
threadGroup.create_thread(boost::bind(&ThreadCheckPrivateSendServer));
else
threadGroup.create_thread(boost::bind(&ThreadCheckPrivateSendClient));
threadGroup.create_thread(boost::bind(&ThreadCheckPrivateSendClient, boost::ref(*g_connman)));
// ********************************************************* Step 12: start node
@ -1986,10 +1998,28 @@ 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);
// Generate coins in the background
GenerateBitcoins(GetBoolArg("-gen", DEFAULT_GENERATE), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams);
GenerateBitcoins(GetBoolArg("-gen", DEFAULT_GENERATE), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams, connman);
// ********************************************************* Step 13: finished
@ -2006,7 +2036,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
threadGroup.create_thread(boost::bind(&ThreadSendAlert));
threadGroup.create_thread(boost::bind(&ThreadSendAlert, boost::ref(connman)));
return !fRequestShutdown;
}

View File

@ -1067,7 +1067,7 @@ bool CTxLockVote::Sign()
void CTxLockVote::Relay() const
{
CInv inv(MSG_TXLOCK_VOTE, GetHash());
RelayInv(inv);
g_connman->RelayInv(inv);
}
bool CTxLockVote::IsExpired(int nHeight) const
@ -1168,7 +1168,7 @@ bool CTxLockCandidate::IsExpired(int nHeight) const
void CTxLockCandidate::Relay() const
{
RelayTransaction(txLockRequest);
g_connman->RelayTransaction(txLockRequest);
std::map<COutPoint, COutPointLock>::const_iterator itOutpointLock = mapOutPointLocks.begin();
while(itOutpointLock != mapOutPointLocks.end()) {
itOutpointLock->second.Relay();

View File

@ -308,12 +308,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;
@ -331,7 +325,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);
@ -339,7 +334,7 @@ void FinalizeNode(NodeId nodeid) {
nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
AddressCurrentlyConnected(state->address);
fUpdateConnectionTime = true;
}
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
@ -577,7 +572,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);
@ -586,7 +580,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);
@ -3317,7 +3310,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 {
@ -3355,6 +3348,9 @@ 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(chainActive.Height());
// Always notify the UI if a new block tip was connected
if (pindexFork != pindexNewTip) {
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
@ -3376,15 +3372,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()) {
@ -3982,7 +3977,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
}
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);
@ -4004,7 +3999,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__);
masternodeSync.IsBlockchainSynced(true);
@ -4969,9 +4964,43 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return true;
}
void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams)
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 uint256 hashSalt;
if (hashSalt.IsNull())
hashSalt = GetRandHash();
uint64_t hashAddr = addr.GetHash();
uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
std::multimap<uint256, CNode*> mapMix;
auto sortfunc = [&mapMix, &hashRand](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION) {
unsigned int nPointer;
memcpy(&nPointer, &pnode, sizeof(nPointer));
uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer);
hashKey = Hash(BEGIN(hashKey), END(hashKey));
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;
@ -4979,7 +5008,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;
@ -5012,7 +5041,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());
@ -5257,10 +5286,12 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
}
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, CConnman& connman)
{
const CChainParams& chainparams = Params();
RandAddSeedPerfmon();
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)
@ -5269,7 +5300,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
if (!(nLocalServices & NODE_BLOOM) &&
if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
(strCommand == NetMsgType::FILTERLOAD ||
strCommand == NetMsgType::FILTERADD ||
strCommand == NetMsgType::FILTERCLEAR))
@ -5311,7 +5342,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)
{
@ -5348,7 +5379,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fRelayTxes = true;
// 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;
@ -5382,7 +5413,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())
{
LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
@ -5395,17 +5426,17 @@ 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);
} else {
if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
{
addrman.Add(addrFrom, addrFrom);
addrman.Good(addrFrom);
connman.AddNewAddress(addrFrom, addrFrom);
connman.MarkAddressGood(addrFrom);
}
}
@ -5468,7 +5499,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)
{
@ -5494,38 +5525,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fReachable = IsReachable(addr);
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 uint256 hashSalt;
if (hashSalt.IsNull())
hashSalt = GetRandHash();
uint64_t hashAddr = addr.GetHash();
uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->nVersion < CADDR_TIME_VERSION)
continue;
unsigned int nPointer;
memcpy(&nPointer, &pnode, sizeof(nPointer));
uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer);
hashKey = Hash(BEGIN(hashKey), END(hashKey));
mapMix.insert(make_pair(hashKey, pnode));
}
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
for (multimap<uint256, 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)
@ -5610,7 +5616,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);
}
@ -5639,7 +5645,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);
}
@ -5827,7 +5833,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
mempool.check(pcoinsTip);
RelayTransaction(tx);
connman.RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
pfrom->nLastTXTime = GetTime();
@ -5863,7 +5869,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
{
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx);
connman.RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
}
@ -5914,7 +5920,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
instantsend.RejectLockRequest(txLockRequest);
// this lets other nodes to create lock request candidate i.e.
// this allows multiple conflicting lock requests to compete for votes
RelayTransaction(tx);
connman.RelayTransaction(tx);
}
if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
@ -5929,7 +5935,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);
connman.RelayTransaction(tx);
} else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
}
@ -6075,7 +6081,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
@ -6103,7 +6109,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
vector<CAddress> vAddr = connman.GetAddresses();
BOOST_FOREACH(const CAddress &addr, vAddr)
pfrom->PushAddress(addr);
}
@ -6111,7 +6117,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::MEMPOOL)
{
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;
@ -6233,9 +6239,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Relay
pfrom->setKnown.insert(alertHash);
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
connman.ForEachNode([&alert](CNode* pnode) {
alert.RelayTo(pnode);
});
}
}
else {
@ -6363,9 +6369,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());
@ -6380,7 +6387,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;
@ -6388,7 +6395,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
@ -6440,7 +6447,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime);
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, connman);
boost::this_thread::interruption_point();
}
catch (const std::ios_base::failure& e)
@ -6484,7 +6491,7 @@ bool ProcessMessages(CNode* pfrom)
}
bool SendMessages(CNode* pto)
bool SendMessages(CNode* pto, CConnman& connman)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
@ -6568,7 +6575,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;
@ -6607,7 +6614,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

@ -36,6 +36,7 @@ class CBlockTreeDB;
class CBloomFilter;
class CChainParams;
class CInv;
class CConnman;
class CScriptCheck;
class CTxMemPool;
class CValidationInterface;
@ -205,7 +206,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) */
@ -223,13 +224,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) */
@ -245,7 +247,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);
double ConvertBitsToDouble(unsigned int nBits);
CAmount GetBlockSubsidy(int nBits, int nHeight, const Consensus::Params& consensusParams, bool fSuperblockPartOnly = false);

View File

@ -781,7 +781,7 @@ void CMasternodePaymentVote::Relay()
// do not relay until synced
if (!masternodeSync.IsWinnersListSynced()) return;
CInv inv(MSG_MASTERNODE_PAYMENT_VOTE, GetHash());
RelayInv(inv);
g_connman->RelayInv(inv);
}
bool CMasternodePaymentVote::CheckSignature(const CPubKey& pubKeyMasternode, int nValidationHeight, int &nDos)

View File

@ -90,7 +90,7 @@ bool CMasternodeSync::IsBlockchainSynced(bool fBlockAccepted)
if(fCheckpointsEnabled && pCurrentBlockIndex->nHeight < Checkpoints::GetTotalBlocksEstimate(Params().Checkpoints()))
return false;
std::vector<CNode*> vNodesCopy = CopyNodeVector();
std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector();
// We have enough peers and assume most of them are synced
if(vNodesCopy.size() >= MASTERNODE_SYNC_ENOUGH_PEERS) {
@ -105,12 +105,12 @@ bool CMasternodeSync::IsBlockchainSynced(bool fBlockAccepted)
if(nNodesAtSameHeight >= MASTERNODE_SYNC_ENOUGH_PEERS) {
LogPrintf("CMasternodeSync::IsBlockchainSynced -- found enough peers on the same height as we are, done\n");
fBlockchainSynced = true;
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return true;
}
}
}
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
// wait for at least one new block to be accepted
if(!fFirstBlockAccepted) return false;
@ -192,12 +192,13 @@ void CMasternodeSync::SwitchToNextAsset()
//try to activate our masternode if possible
activeMasternode.ManageState();
TRY_LOCK(cs_vNodes, lockRecv);
if(lockRecv) {
BOOST_FOREACH(CNode* pnode, vNodes) {
netfulfilledman.AddFulfilledRequest(pnode->addr, "full-sync");
}
}
// TODO: Find out whether we can just use LOCK instead of:
// TRY_LOCK(cs_vNodes, lockRecv);
// if(lockRecv) { ... }
g_connman->ForEachNode([](CNode* pnode) {
netfulfilledman.AddFulfilledRequest(pnode->addr, "full-sync");
});
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Sync has finished\n");
break;
@ -237,17 +238,17 @@ void CMasternodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDat
void CMasternodeSync::ClearFulfilledRequests()
{
TRY_LOCK(cs_vNodes, lockRecv);
if(!lockRecv) return;
// TODO: Find out whether we can just use LOCK instead of:
// TRY_LOCK(cs_vNodes, lockRecv);
// if(!lockRecv) return;
BOOST_FOREACH(CNode* pnode, vNodes)
{
g_connman->ForEachNode([](CNode* pnode) {
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "spork-sync");
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "masternode-list-sync");
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "masternode-payment-sync");
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "governance-sync");
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "full-sync");
}
});
}
void CMasternodeSync::ProcessTick()
@ -271,9 +272,9 @@ void CMasternodeSync::ProcessTick()
LogPrintf("CMasternodeSync::ProcessTick -- WARNING: not enough data, restarting sync\n");
Reset();
} else {
std::vector<CNode*> vNodesCopy = CopyNodeVector();
std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector();
governance.RequestGovernanceObjectVotes(vNodesCopy);
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
}
@ -309,7 +310,7 @@ void CMasternodeSync::ProcessTick()
SwitchToNextAsset();
}
std::vector<CNode*> vNodesCopy = CopyNodeVector();
std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector();
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
@ -334,7 +335,7 @@ void CMasternodeSync::ProcessTick()
nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
}
nRequestedMasternodeAttempt++;
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
@ -370,11 +371,11 @@ void CMasternodeSync::ProcessTick()
LogPrintf("CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName());
// there is no way we can continue without masternode list, fail here and try later
Fail();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
SwitchToNextAsset();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
@ -387,7 +388,7 @@ void CMasternodeSync::ProcessTick()
mnodeman.DsegUpdate(pnode);
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return; //this will cause each peer to get one request each six seconds for the various assets we need
}
@ -404,11 +405,11 @@ void CMasternodeSync::ProcessTick()
LogPrintf("CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName());
// probably not a good idea to proceed without winner list
Fail();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
SwitchToNextAsset();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
@ -418,7 +419,7 @@ void CMasternodeSync::ProcessTick()
if(nRequestedMasternodeAttempt > 1 && mnpayments.IsEnoughData()) {
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- found enough data\n", nTick, nRequestedMasternodeAssets);
SwitchToNextAsset();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
@ -434,7 +435,7 @@ void CMasternodeSync::ProcessTick()
// ask node for missing pieces only (old nodes will not be asked)
mnpayments.RequestLowDataPaymentBlocks(pnode);
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return; //this will cause each peer to get one request each six seconds for the various assets we need
}
@ -451,7 +452,7 @@ void CMasternodeSync::ProcessTick()
// it's kind of ok to skip this for now, hopefully we'll catch up later?
}
SwitchToNextAsset();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
@ -480,7 +481,7 @@ void CMasternodeSync::ProcessTick()
// reset nTimeNoObjectsLeft to be able to use the same condition on resync
nTimeNoObjectsLeft = 0;
SwitchToNextAsset();
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return;
}
nLastTick = nTick;
@ -495,13 +496,13 @@ void CMasternodeSync::ProcessTick()
SendGovernanceSyncRequest(pnode);
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return; //this will cause each peer to get one request each six seconds for the various assets we need
}
}
}
// looped through all nodes, release them
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
}
void CMasternodeSync::SendGovernanceSyncRequest(CNode* pnode)

View File

@ -756,7 +756,7 @@ bool CMasternodeBroadcast::CheckSignature(int& nDos)
void CMasternodeBroadcast::Relay()
{
CInv inv(MSG_MASTERNODE_ANNOUNCE, GetHash());
RelayInv(inv);
g_connman->RelayInv(inv);
}
CMasternodePing::CMasternodePing(CTxIn& vinNew) :
@ -916,7 +916,7 @@ bool CMasternodePing::CheckAndUpdate(CMasternode* pmn, bool fFromNewBroadcast, i
void CMasternodePing::Relay()
{
CInv inv(MSG_MASTERNODE_PING, GetHash());
RelayInv(inv);
g_connman->RelayInv(inv);
}
void CMasternode::AddGovernanceVote(uint256 nGovernanceObjectHash)

View File

@ -472,7 +472,7 @@ public:
void Relay() const
{
CInv inv(MSG_MASTERNODE_VERIFY, GetHash());
RelayInv(inv);
g_connman->RelayInv(inv);
}
};

View File

@ -763,14 +763,13 @@ void CMasternodeMan::ProcessMasternodeConnections()
//we don't care about this for regtest
if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return;
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
g_connman->ForEachNode([](CNode* pnode) {
if(pnode->fMasternode) {
if(privateSendClient.infoMixingMasternode.fInfoValid && pnode->addr == privateSendClient.infoMixingMasternode.addr) continue;
if(privateSendClient.infoMixingMasternode.fInfoValid && pnode->addr == privateSendClient.infoMixingMasternode.addr) return true;
LogPrintf("Closing Masternode connection: peer=%d, addr=%s\n", pnode->id, pnode->addr.ToString());
pnode->fDisconnect = true;
}
}
});
}
std::pair<CService, std::set<uint256> > CMasternodeMan::PopScheduledMnbRequestConnection()
@ -819,7 +818,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
if (CheckMnbAndUpdateMasternodeList(pfrom, mnb, nDos)) {
// use announced Masternode as a peer
addrman.Add(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2*60*60);
g_connman->AddNewAddress(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2*60*60);
} else if(nDos > 0) {
Misbehaving(pfrom->GetId(), nDos);
}
@ -1098,7 +1097,8 @@ bool CMasternodeMan::SendVerifyRequest(const CAddress& addr, const std::vector<C
return false;
}
CNode* pnode = ConnectNode(addr, NULL, true);
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = g_connman->ConnectNode(addr, NULL, true);
if(pnode == NULL) {
LogPrintf("CMasternodeMan::SendVerifyRequest -- can't connect to node to verify it, addr=%s\n", addr.ToString());
return false;

View File

@ -376,7 +376,7 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
// }
//}
static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams)
static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams, CConnman* connman)
{
LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
@ -393,14 +393,14 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar
// Process this block the same as if we had received it from another node
CValidationState state;
if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL))
if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, connman))
return error("ProcessBlockFound -- ProcessNewBlock() failed, block not accepted");
return true;
}
// ***TODO*** that part changed in bitcoin, we are using a mix with old one here for now
void static BitcoinMiner(const CChainParams& chainparams)
void static BitcoinMiner(const CChainParams& chainparams, CConnman& connman)
{
LogPrintf("DashMiner -- started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
@ -423,11 +423,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
// Busy-wait for the network to come online so we don't waste time mining
// on an obsolete chain. In regtest mode we expect to fly solo.
do {
bool fvNodesEmpty;
{
LOCK(cs_vNodes);
fvNodesEmpty = vNodes.empty();
}
bool fvNodesEmpty = connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0;
if (!fvNodesEmpty && !IsInitialBlockDownload() && masternodeSync.IsSynced())
break;
MilliSleep(1000);
@ -472,7 +468,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
// Found a solution
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("DashMiner:\n proof-of-work found\n hash: %s\n target: %s\n", hash.GetHex(), hashTarget.GetHex());
ProcessBlockFound(pblock, chainparams);
ProcessBlockFound(pblock, chainparams, &connman);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
coinbaseScript->KeepScript();
@ -492,7 +488,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
// Check for stop or if block needs to be rebuilt
boost::this_thread::interruption_point();
// Regtest mode doesn't require peers
if (vNodes.empty() && chainparams.MiningRequiresPeers())
if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers())
break;
if (pblock->nNonce >= 0xffff0000)
break;
@ -525,7 +521,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
}
}
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams)
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams, CConnman& connman)
{
static boost::thread_group* minerThreads = NULL;
@ -544,5 +540,5 @@ void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainpar
minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++)
minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams)));
minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams), boost::ref(connman)));
}

View File

@ -12,6 +12,7 @@
class CBlockIndex;
class CChainParams;
class CConnman;
class CReserveKey;
class CScript;
class CWallet;
@ -30,7 +31,7 @@ struct CBlockTemplate
};
/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams, CConnman& connman);
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn);
/** Modify the extranonce in a block */

File diff suppressed because it is too large Load Diff

568
src/net.h
View File

@ -6,6 +6,8 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
#include "addrdb.h"
#include "addrman.h"
#include "bloom.h"
#include "compat.h"
#include "limitedmap.h"
@ -20,6 +22,7 @@
#include <atomic>
#include <deque>
#include <stdint.h>
#include <memory>
#ifndef WIN32
#include <arpa/inet.h>
@ -53,6 +56,10 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
/** 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;
/** Maximum number if outgoing masternodes */
static const int MAX_OUTBOUND_MASTERNODE_CONNECTIONS = 20;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@ -81,27 +88,330 @@ 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);
// fConnectToMasternode should be 'true' only if you want this node to allow to connect to itself
// and/or you want it to be disconnected on CMasternodeMan::ProcessMasternodeConnections()
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL, bool fConnectToMasternode = false);
bool OpenNetworkConnection(const CAddress& addrConnect, 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, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
bool CheckIncomingNonce(uint64_t nonce);
// fConnectToMasternode should be 'true' only if you want this node to allow to connect to itself
// and/or you want it to be disconnected on CMasternodeMan::ProcessMasternodeConnections()
// Unfortunately, can't make this method private like in Bitcoin,
// because it's used in many Dash-specific places (masternode, privatesend).
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL, bool fConnectToMasternode = false);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
bool ForNode(const CService& addr, 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();
};
std::vector<CNode*> CopyNodeVector();
void ReleaseNodeVector(const std::vector<CNode*>& vecNodes);
void RelayTransaction(const CTransaction& tx);
void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION);
// 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();
void ThreadMnbRequestConnections();
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& addr);
bool AttemptToEvictConnection();
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;
CSemaphore *semMasternodeOutbound;
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);
typedef int NodeId;
size_t SocketSendData(CNode *pnode);
struct CombinerAll
{
@ -121,11 +431,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;
};
@ -156,31 +465,17 @@ 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 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 std::map<CInv, CDataStream> mapRelay;
extern std::deque<std::pair<int64_t, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
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;
@ -261,67 +556,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
{
@ -333,6 +567,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;
@ -381,17 +616,6 @@ public:
NodeId id;
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;
@ -439,22 +663,10 @@ public:
std::vector<unsigned char> vchKeyedNetGroup;
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false, bool fNetworkNodeIn = false);
CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false, bool fNetworkNodeIn = 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;
// Secret key for computing keyed net groups
static std::vector<unsigned char> vchSecretKey;
@ -463,12 +675,19 @@ private:
CNode(const CNode&);
void operator=(const CNode&);
uint64_t nLocalHostNonce;
ServiceFlags nLocalServices;
int nMyStartingHeight;
public:
NodeId GetId() const {
return id;
}
uint64_t GetLocalNonce() const {
return nLocalHostNonce;
}
int GetRefCount()
{
LOCK(cs_nRefCount);
@ -486,7 +705,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)
@ -781,69 +1000,12 @@ 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;
}
static std::vector<unsigned char> CalculateKeyedNetGroup(CAddress& address);
};
@ -854,49 +1016,9 @@ public:
static void callCleanup();
};
class CTransaction;
void RelayTransaction(const CTransaction& tx);
void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION);
/** 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);
std::vector<CNode*> CopyNodeVector();
void ReleaseNodeVector(const std::vector<CNode*>& vecNodes);
struct AddedNodeInfo
{
std::string strAddedNode;
CService resolvedAddress;
bool fConnected;
bool fInbound;
};
std::vector<AddedNodeInfo> GetAddedNodeInfo();
#endif // BITCOIN_NET_H

View File

@ -656,7 +656,7 @@ bool CPrivateSendClient::CheckAutomaticBackup()
//
// Passively run mixing in the background to anonymize funds based on the given configuration.
//
bool CPrivateSendClient::DoAutomaticDenominating(bool fDryRun)
bool CPrivateSendClient::DoAutomaticDenominating(CConnman& connman, bool fDryRun)
{
if(!fEnablePrivateSend || fMasterNode || !pCurrentBlockIndex) return false;
if(!pwalletMain || pwalletMain->IsLocked(true)) return false;
@ -737,11 +737,11 @@ bool CPrivateSendClient::DoAutomaticDenominating(bool fDryRun)
// there are funds to denominate and denominated balance does not exceed
// max amount to mix yet.
if(nBalanceAnonimizableNonDenom >= nValueMin + CPrivateSend::GetCollateralAmount() && nBalanceDenominated < nPrivateSendAmount*COIN)
return CreateDenominated();
return CreateDenominated(connman);
//check if we have the collateral sized inputs
if(!pwalletMain->HasCollateralInputs())
return !pwalletMain->HasCollateralInputs(false) && MakeCollateralAmounts();
return !pwalletMain->HasCollateralInputs(false) && MakeCollateralAmounts(connman);
if(nSessionID) {
strAutoDenomResult = _("Mixing in progress...");
@ -849,21 +849,23 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized)
vecMasternodesUsed.push_back(dsq.vin);
CNode* pnodeFound = NULL;
{
LOCK(cs_vNodes);
pnodeFound = FindNode(infoMn.addr);
if(pnodeFound) {
if(pnodeFound->fDisconnect) {
continue;
} else {
pnodeFound->AddRef();
}
bool fDisconnect = false;
g_connman->ForNode(infoMn.addr, [&pnodeFound, &fDisconnect](CNode* pnode) {
pnodeFound = pnode;
if(pnodeFound->fDisconnect) {
fDisconnect = true;
} else {
pnodeFound->AddRef();
}
}
return true;
});
if (fDisconnect)
continue;
LogPrintf("CPrivateSendClient::JoinExistingQueue -- attempt to connect to masternode from queue, addr=%s\n", infoMn.addr.ToString());
// connect to Masternode and submit the queue request
CNode* pnode = (pnodeFound && pnodeFound->fMasternode) ? pnodeFound : ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true);
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = (pnodeFound && pnodeFound->fMasternode) ? pnodeFound : g_connman->ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true);
if(pnode) {
infoMixingMasternode = infoMn;
nSessionDenom = dsq.nDenom;
@ -922,21 +924,24 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA
}
CNode* pnodeFound = NULL;
{
LOCK(cs_vNodes);
pnodeFound = FindNode(infoMn.addr);
if(pnodeFound) {
if(pnodeFound->fDisconnect) {
nTries++;
continue;
} else {
pnodeFound->AddRef();
}
bool fDisconnect = false;
g_connman->ForNode(infoMn.addr, [&pnodeFound, &fDisconnect](CNode* pnode) {
pnodeFound = pnode;
if(pnodeFound->fDisconnect) {
fDisconnect = true;
} else {
pnodeFound->AddRef();
}
return true;
});
if (fDisconnect) {
nTries++;
continue;
}
LogPrintf("CPrivateSendClient::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, infoMn.addr.ToString());
CNode* pnode = (pnodeFound && pnodeFound->fMasternode) ? pnodeFound : ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true);
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = (pnodeFound && pnodeFound->fMasternode) ? pnodeFound : g_connman->ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true);
if(pnode) {
LogPrintf("CPrivateSendClient::StartNewQueue -- connected, addr=%s\n", infoMn.addr.ToString());
infoMixingMasternode = infoMn;
@ -1121,7 +1126,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
}
// Create collaterals by looping through inputs grouped by addresses
bool CPrivateSendClient::MakeCollateralAmounts()
bool CPrivateSendClient::MakeCollateralAmounts(CConnman& connman)
{
std::vector<CompactTallyItem> vecTally;
if(!pwalletMain->SelectCoinsGrouppedByAddresses(vecTally, false)) {
@ -1131,13 +1136,13 @@ bool CPrivateSendClient::MakeCollateralAmounts()
// First try to use only non-denominated funds
BOOST_FOREACH(CompactTallyItem& item, vecTally) {
if(!MakeCollateralAmounts(item, false)) continue;
if(!MakeCollateralAmounts(item, false, connman)) continue;
return true;
}
// There should be at least some denominated funds we should be able to break in pieces to continue mixing
BOOST_FOREACH(CompactTallyItem& item, vecTally) {
if(!MakeCollateralAmounts(item, true)) continue;
if(!MakeCollateralAmounts(item, true, connman)) continue;
return true;
}
@ -1147,7 +1152,7 @@ bool CPrivateSendClient::MakeCollateralAmounts()
}
// Split up large inputs or create fee sized inputs
bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated)
bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated, CConnman& connman)
{
LOCK2(cs_main, pwalletMain->cs_wallet);
@ -1204,7 +1209,7 @@ bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem
LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- txid=%s\n", wtx.GetHash().GetHex());
// use the same nCachedLastSuccessBlock as for DS mixinx to prevent race
if(!pwalletMain->CommitTransaction(wtx, reservekeyChange)) {
if(!pwalletMain->CommitTransaction(wtx, reservekeyChange, &connman)) {
LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- CommitTransaction failed!\n");
return false;
}
@ -1215,7 +1220,7 @@ bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem
}
// Create denominations by looping through inputs grouped by addresses
bool CPrivateSendClient::CreateDenominated()
bool CPrivateSendClient::CreateDenominated(CConnman& connman)
{
LOCK2(cs_main, pwalletMain->cs_wallet);
@ -1228,7 +1233,7 @@ bool CPrivateSendClient::CreateDenominated()
bool fCreateMixingCollaterals = !pwalletMain->HasCollateralInputs();
BOOST_FOREACH(CompactTallyItem& item, vecTally) {
if(!CreateDenominated(item, fCreateMixingCollaterals)) continue;
if(!CreateDenominated(item, fCreateMixingCollaterals, connman)) continue;
return true;
}
@ -1237,7 +1242,7 @@ bool CPrivateSendClient::CreateDenominated()
}
// Create denominations
bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals)
bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals, CConnman& connman)
{
std::vector<CRecipient> vecSend;
CAmount nValueLeft = tallyItem.nAmount;
@ -1351,7 +1356,7 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo
reservekeyCollateral.KeepKey();
LogPrintf("CPrivateSendClient::CreateDenominated -- %d keys keeped\n", reservekeyDenomVec.size() + 1);
if(!pwalletMain->CommitTransaction(wtx, reservekeyChange)) {
if(!pwalletMain->CommitTransaction(wtx, reservekeyChange, &connman)) {
LogPrintf("CPrivateSendClient::CreateDenominated -- CommitTransaction failed!\n");
return false;
}
@ -1367,12 +1372,11 @@ void CPrivateSendClient::RelayIn(const CDarkSendEntry& entry)
{
if(!infoMixingMasternode.fInfoValid) return;
LOCK(cs_vNodes);
CNode* pnode = FindNode(infoMixingMasternode.addr);
if(pnode != NULL) {
g_connman->ForNode(infoMixingMasternode.addr, [&entry](CNode* pnode) {
LogPrintf("CPrivateSendClient::RelayIn -- found master, relaying message to %s\n", pnode->addr.ToString());
pnode->PushMessage(NetMsgType::DSVIN, entry);
}
return true;
});
}
void CPrivateSendClient::SetState(PoolState nStateNew)
@ -1394,7 +1398,7 @@ void CPrivateSendClient::UpdatedBlockTip(const CBlockIndex *pindex)
}
//TODO: Rename/move to core
void ThreadCheckPrivateSendClient()
void ThreadCheckPrivateSendClient(CConnman& connman)
{
if(fLiteMode) return; // disable all Dash specific functionality
@ -1416,7 +1420,7 @@ void ThreadCheckPrivateSendClient()
nTick++;
privateSendClient.CheckTimeout();
if(nDoAutoNextRun == nTick) {
privateSendClient.DoAutomaticDenominating();
privateSendClient.DoAutomaticDenominating(connman);
nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN + GetRandInt(PRIVATESEND_AUTO_TIMEOUT_MAX - PRIVATESEND_AUTO_TIMEOUT_MIN);
}
}

View File

@ -10,6 +10,7 @@
#include "wallet/wallet.h"
class CPrivateSendClient;
class CConnman;
static const int DENOMS_COUNT_MAX = 100;
@ -66,12 +67,12 @@ private:
bool StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsAnonymized);
/// Create denominations
bool CreateDenominated();
bool CreateDenominated(const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals);
bool CreateDenominated(CConnman& connman);
bool CreateDenominated(const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals, CConnman& connman);
/// Split up large inputs or make fee sized inputs
bool MakeCollateralAmounts();
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated);
bool MakeCollateralAmounts(CConnman& connman);
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated, CConnman& connman);
/// As a client, submit part of a future mixing transaction to a Masternode to start the process
bool SubmitDenominate();
@ -128,7 +129,7 @@ public:
std::string GetStatus();
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(bool fDryRun=false);
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun=false);
void CheckTimeout();
@ -138,6 +139,6 @@ public:
void UpdatedBlockTip(const CBlockIndex *pindex);
};
void ThreadCheckPrivateSendClient();
void ThreadCheckPrivateSendClient(CConnman& connman);
#endif

View File

@ -367,7 +367,7 @@ void CPrivateSendServer::CommitFinalTransaction()
LogPrintf("CPrivateSendServer::CommitFinalTransaction -- TRANSMITTING DSTX\n");
CInv inv(MSG_DSTX, hashTx);
RelayInv(inv);
g_connman->RelayInv(inv);
// Tell the clients it was successful
RelayCompletedTransaction(MSG_SUCCESS);
@ -452,7 +452,7 @@ void CPrivateSendServer::ChargeFees()
// should never really happen
LogPrintf("CPrivateSendServer::ChargeFees -- ERROR: AcceptToMemoryPool failed!\n");
} else {
RelayTransaction(vecOffendersCollaterals[0]);
g_connman->RelayTransaction(vecOffendersCollaterals[0]);
}
}
}
@ -487,7 +487,7 @@ void CPrivateSendServer::ChargeRandomFees()
// should never really happen
LogPrintf("CPrivateSendServer::ChargeRandomFees -- ERROR: AcceptToMemoryPool failed!\n");
} else {
RelayTransaction(txCollateral);
g_connman->RelayTransaction(txCollateral);
}
}
}
@ -795,10 +795,10 @@ bool CPrivateSendServer::AddUserToExistingSession(int nDenom, CTransaction txCol
void CPrivateSendServer::RelayFinalTransaction(const CTransaction& txFinal)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
g_connman->ForEachNode([&txFinal, this](CNode* pnode) {
if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION)
pnode->PushMessage(NetMsgType::DSFINALTX, nSessionID, txFinal);
});
}
void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID)
@ -809,18 +809,18 @@ void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate
void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
g_connman->ForEachNode([nStatusUpdate, nMessageID, this](CNode* pnode) {
if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION)
PushStatus(pnode, nStatusUpdate, nMessageID);
});
}
void CPrivateSendServer::RelayCompletedTransaction(PoolMessage nMessageID)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
g_connman->ForEachNode([nMessageID, this](CNode* pnode) {
if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION)
pnode->PushMessage(NetMsgType::DSCOMPLETE, nSessionID, (int)nMessageID);
});
}
void CPrivateSendServer::SetState(PoolState nStateNew)

View File

@ -74,12 +74,12 @@ bool CDarksendQueue::CheckSignature(const CPubKey& pubKeyMasternode)
bool CDarksendQueue::Relay()
{
std::vector<CNode*> vNodesCopy = CopyNodeVector();
std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector();
BOOST_FOREACH(CNode* pnode, vNodesCopy)
if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION)
pnode->PushMessage(NetMsgType::DSQUEUE, (*this));
ReleaseNodeVector(vNodesCopy);
g_connman->ReleaseNodeVector(vNodesCopy);
return true;
}

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

@ -62,16 +62,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;
}
QString ClientModel::getMasternodeCountString() const
@ -94,12 +96,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

@ -290,17 +290,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

@ -569,7 +569,7 @@ void OverviewPage::privateSendStatus()
}
void OverviewPage::privateSendAuto(){
privateSendClient.DoAutomaticDenominating();
privateSendClient.DoAutomaticDenominating(*g_connman);
}
void OverviewPage::privateSendReset(){

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

@ -918,34 +918,31 @@ 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);
CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
}
g_connman->Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
}
void RPCConsole::unbanSelectedNode()
@ -954,12 +951,12 @@ 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(strNode.toStdString());
if (possibleSubnet.IsValid())
if (possibleSubnet.IsValid() && g_connman)
{
CNode::Unban(possibleSubnet);
g_connman->Unban(possibleSubnet);
clientModel->getBanTableModel()->refresh();
}
}

View File

@ -380,7 +380,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
CReserveKey *keyChange = transaction.getPossibleKeyChange();
if(!wallet->CommitTransaction(*newTx, *keyChange, recipients[0].fUseInstantSend ? NetMsgType::TXLOCKREQUEST : NetMsgType::TX))
if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get(), recipients[0].fUseInstantSend ? NetMsgType::TXLOCKREQUEST : NetMsgType::TX))
return TransactionCommitFailed;
CTransaction* t = (CTransaction*)newTx;

View File

@ -1007,7 +1007,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
}
if (state.IsValid()) {
ActivateBestChain(state, Params());
ActivateBestChain(state, Params(), NULL, g_connman.get());
}
if (!state.IsValid()) {
@ -1046,7 +1046,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
}
if (state.IsValid()) {
ActivateBestChain(state, Params());
ActivateBestChain(state, Params(), NULL, g_connman.get());
}
if (!state.IsValid()) {

View File

@ -168,7 +168,7 @@ UniValue gobject(const UniValue& params, bool fHelp)
// -- make our change address
CReserveKey reservekey(pwalletMain);
// -- send the tx to the network
pwalletMain->CommitTransaction(wtx, reservekey, NetMsgType::TX);
pwalletMain->CommitTransaction(wtx, reservekey, g_connman.get(), NetMsgType::TX);
DBG( cout << "gobject: prepare "
<< " strData = " << govobj.GetDataAsString()

View File

@ -44,7 +44,7 @@ UniValue privatesend(const UniValue& params, bool fHelp)
return "Mixing is not supported from masternodes";
privateSendClient.fEnablePrivateSend = true;
bool result = privateSendClient.DoAutomaticDenominating();
bool result = privateSendClient.DoAutomaticDenominating(*g_connman);
return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatus() + ", will retry"));
}
@ -147,7 +147,8 @@ UniValue masternode(const UniValue& params, bool fHelp)
CService addr = CService(strAddress);
CNode *pnode = ConnectNode(CAddress(addr, NODE_NETWORK), NULL);
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode *pnode = g_connman->ConnectNode(CAddress(addr, NODE_NETWORK), NULL);
if(!pnode)
throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Couldn't connect to masternode %s", strAddress));

View File

@ -178,7 +178,7 @@ UniValue generate(const UniValue& params, bool fHelp)
++pblock->nNonce;
}
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());
@ -228,7 +228,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
mapArgs["-gen"] = (fGenerate ? "1" : "0");
mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
GenerateBitcoins(fGenerate, nGenProcLimit, Params());
GenerateBitcoins(fGenerate, nGenProcLimit, Params(), *g_connman);
return NullUniValue;
}
@ -490,7 +490,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, "Dash Core is not connected!");
if (IsInitialBlockDownload())
@ -794,7 +797,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

@ -97,7 +97,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()));
@ -508,14 +509,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

@ -37,9 +37,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)
@ -55,29 +56,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)
@ -128,10 +116,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);
@ -213,32 +202,27 @@ UniValue addnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("addnode", "\"192.168.0.6:9999\", \"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, NULL, strNode.c_str());
g_connman->OpenNetworkConnection(addr, 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;
@ -257,11 +241,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() == 2) {
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;
}
@ -436,14 +426,15 @@ 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("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);
@ -483,6 +474,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;
@ -501,7 +494,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
@ -512,11 +505,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;
@ -533,8 +526,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++)
@ -562,8 +558,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

@ -883,7 +883,13 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
if (fInstantSend && !instantsend.ProcessTxLockRequest(tx)) {
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Not a valid InstantSend transaction, see debug.log for more info");
}
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

@ -23,7 +23,7 @@ If you screw up something, send another alert with nCancel set to cancel
the bad alert.
*/
void ThreadSendAlert()
void ThreadSendAlert(CConnman& connman)
{
if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert"))
return;
@ -91,7 +91,7 @@ void ThreadSendAlert()
// Confirm
if (!mapArgs.count("-sendalert"))
return;
while (vNodes.empty() && !ShutdownRequested())
while (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && !ShutdownRequested())
MilliSleep(500);
if (ShutdownRequested())
return;
@ -100,15 +100,13 @@ void ThreadSendAlert()
printf("ThreadSendAlert() : Sending alert\n");
int nSent = 0;
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
g_connman->ForEachNode([&alert2, &nSent](CNode* pnode) {
if (alert2.RelayTo(pnode))
{
printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str());
nSent++;
}
}
});
}
printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent);
}

View File

@ -259,5 +259,5 @@ bool CSporkMessage::CheckSignature()
void CSporkMessage::Relay()
{
CInv inv(MSG_SPORK, GetHash());
RelayInv(inv);
g_connman->RelayInv(inv);
}

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

@ -118,7 +118,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

@ -145,6 +145,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;
@ -154,12 +156,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

@ -30,6 +30,8 @@
CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h
CWallet* pwalletMain;
std::unique_ptr<CConnman> g_connman;
extern bool fPrintToConsole;
extern void noui_connect();
@ -47,6 +49,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
g_connman.reset();
}
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
@ -72,6 +75,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());
}
@ -131,7 +136,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

@ -24,10 +24,12 @@ struct BasicTestingSetup {
* Included are data directory, coins database, script check threads
* and wallet (if enabled) 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

@ -19,7 +19,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));
@ -29,7 +29,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

@ -12,6 +12,7 @@
class CBlock;
struct CBlockLocator;
class CBlockIndex;
class CConnman;
class CReserveScript;
class CTransaction;
class CValidationInterface;
@ -37,7 +38,7 @@ protected:
virtual void SetBestChain(const CBlockLocator &locator) {}
virtual bool UpdatedTransaction(const uint256 &hash) { return false;}
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) {};
@ -60,7 +61,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

@ -382,6 +382,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 Dash address
CScript scriptPubKey = GetScriptForDestination(address);
@ -399,7 +402,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, fUseInstantSend ? NetMsgType::TXLOCKREQUEST : NetMsgType::TX))
if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get(), fUseInstantSend ? NetMsgType::TXLOCKREQUEST : NetMsgType::TX))
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 wallet.dat and coins were spent in the copy but not marked as spent here.");
}
@ -1053,6 +1056,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;
@ -1123,7 +1129,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
NULL, true, fUsePrivateSend ? ONLY_DENOMINATED : ALL_COINS, fUseInstantSend);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
if (!pwalletMain->CommitTransaction(wtx, keyChange, fUseInstantSend ? NetMsgType::TXLOCKREQUEST : NetMsgType::TX))
if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get(), fUseInstantSend ? NetMsgType::TXLOCKREQUEST : NetMsgType::TX))
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
return wtx.GetHash().GetHex();
@ -2503,9 +2509,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

@ -1751,7 +1751,7 @@ void CWallet::ReacceptWalletTransactions()
}
}
bool CWalletTx::RelayWalletTransaction(std::string strCommand)
bool CWalletTx::RelayWalletTransaction(CConnman* connman, std::string strCommand)
{
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
@ -1763,8 +1763,10 @@ bool CWalletTx::RelayWalletTransaction(std::string strCommand)
if(strCommand == NetMsgType::TXLOCKREQUEST) {
instantsend.ProcessTxLockRequest(((CTxLockRequest)*this));
}
RelayTransaction((CTransaction)*this);
return true;
if (connman) {
connman->RelayTransaction((CTransaction)*this);
return true;
}
}
}
return false;
@ -2070,7 +2072,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;
@ -2088,13 +2090,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.
@ -2112,7 +2114,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());
}
@ -3528,7 +3530,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, std::string strCommand)
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, std::string strCommand)
{
{
LOCK2(cs_main, cs_wallet);
@ -3574,7 +3576,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std:
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
}
wtxNew.RelayWalletTransaction(strCommand);
wtxNew.RelayWalletTransaction(connman, strCommand);
}
}
return true;

View File

@ -468,7 +468,7 @@ public:
int64_t GetTxTime() const;
int GetRequestCount() const;
bool RelayWalletTransaction(std::string strCommand="tx");
bool RelayWalletTransaction(CConnman* connman, std::string strCommand="tx");
std::set<uint256> GetConflicts() const;
};
@ -862,8 +862,8 @@ public:
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, 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;
@ -893,7 +893,7 @@ public:
*/
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend=false);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand="tx");
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, std::string strCommand="tx");
bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason);
bool ConvertList(std::vector<CTxIn> vecTxIn, std::vector<CAmount>& vecAmounts);