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:
parent
15958c594c
commit
a9d771e497
@ -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 \
|
||||
|
@ -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
218
src/addrdb.cpp
Normal 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
103
src/addrdb.h
Normal 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
|
@ -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));
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
64
src/init.cpp
64
src/init.cpp
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
157
src/main.cpp
157
src/main.cpp
@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
|
10
src/main.h
10
src/main.h
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -472,7 +472,7 @@ public:
|
||||
void Relay() const
|
||||
{
|
||||
CInv inv(MSG_MASTERNODE_VERIFY, GetHash());
|
||||
RelayInv(inv);
|
||||
g_connman->RelayInv(inv);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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 */
|
||||
|
845
src/net.cpp
845
src/net.cpp
File diff suppressed because it is too large
Load Diff
568
src/net.h
568
src/net.h
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -569,7 +569,7 @@ void OverviewPage::privateSendStatus()
|
||||
}
|
||||
|
||||
void OverviewPage::privateSendAuto(){
|
||||
privateSendClient.DoAutomaticDenominating();
|
||||
privateSendClient.DoAutomaticDenominating(*g_connman);
|
||||
}
|
||||
|
||||
void OverviewPage::privateSendReset(){
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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()
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
108
src/rpc/net.cpp
108
src/rpc/net.cpp
@ -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;
|
||||
}
|
||||
|
@ -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.)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -259,5 +259,5 @@ bool CSporkMessage::CheckSignature()
|
||||
void CSporkMessage::Relay()
|
||||
{
|
||||
CInv inv(MSG_SPORK, GetHash());
|
||||
RelayInv(inv);
|
||||
g_connman->RelayInv(inv);
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -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) */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user