Merge #8085: p2p: Begin encapsulation
0103c5b
net: move MAX_FEELER_CONNECTIONS into connman (Cory Fields)e700cd0
Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead (Jeremy Rubin)d1a2295
Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting (Jeremy Rubin)98591c5
net: move vNodesDisconnected into CConnman (Cory Fields)fa2f8bc
net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options (Cory Fields)a19553b
net: Introduce CConnection::Options to avoid passing so many params (Cory Fields)bafa5fc
net: Drop StartNode/StopNode and use CConnman directly (Cory Fields)e81a602
net: pass CClientUIInterface into CConnman (Cory Fields)f60b905
net: Pass best block known height into CConnman (Cory Fields)fdf69ff
net: move max/max-outbound to CConnman (Cory Fields)8a59369
net: move semOutbound to CConnman (Cory Fields)bd72937
net: move nLocalServices/nRelevantServices to CConnman (Cory Fields)be9c796
net: move SendBufferSize/ReceiveFloodSize to CConnman (Cory Fields)63cafa6
net: move send/recv statistics to CConnman (Cory Fields)adf5d4c
net: SocketSendData returns written size (Cory Fields)ee44fa9
net: move messageHandlerCondition to CConnman (Cory Fields)960cf2e
net: move nLocalHostNonce to CConnman (Cory Fields)551e088
net: move nLastNodeId to CConnman (Cory Fields)6c19d92
net: move whitelist functions into CConnman (Cory Fields)53347f0
net: create generic functor accessors and move vNodes to CConnman (Cory Fields)c0569c7
net: Add most functions needed for vNodes to CConnman (Cory Fields)8ae2dac
net: move added node functions to CConnman (Cory Fields)502dd3a
net: Add oneshot functions to CConnman (Cory Fields)a0f3d3c
net: move ban and addrman functions into CConnman (Cory Fields)aaf018e
net: handle nodesignals in CConnman (Cory Fields)b1a5f43
net: move OpenNetworkConnection into CConnman (Cory Fields)02137f1
net: Move socket binding into CConnman (Cory Fields)5b446dd
net: Pass CConnection to wallet rather than using the global (Cory Fields)8d58c4d
net: Pass CConnman around as needed (Cory Fields)d7349ca
net: Add rpc error for missing/disabled p2p functionality (Cory Fields)cd16f48
net: Create CConnman to encapsulate p2p connections (Cory Fields)d93b14d
net: move CBanDB and CAddrDB out of net.h/cpp (Cory Fields)531214f
gui: add NodeID to the peer table (Cory Fields)
This commit is contained in:
commit
6423116741
32 changed files with 1383 additions and 905 deletions
|
@ -71,6 +71,7 @@ endif
|
|||
.PHONY: FORCE check-symbols check-security
|
||||
# bitcoin core #
|
||||
BITCOIN_CORE_H = \
|
||||
addrdb.h \
|
||||
addrman.h \
|
||||
base58.h \
|
||||
bloom.h \
|
||||
|
@ -164,6 +165,7 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
|
|||
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libbitcoin_server_a_SOURCES = \
|
||||
addrman.cpp \
|
||||
addrdb.cpp \
|
||||
bloom.cpp \
|
||||
blockencodings.cpp \
|
||||
chain.cpp \
|
||||
|
|
218
src/addrdb.cpp
Normal file
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
|
54
src/init.cpp
54
src/init.cpp
|
@ -42,6 +42,7 @@
|
|||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <signal.h>
|
||||
|
@ -70,6 +71,7 @@ static const bool DEFAULT_REST_ENABLE = false;
|
|||
static const bool DEFAULT_DISABLE_SAFEMODE = false;
|
||||
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
|
||||
|
||||
std::unique_ptr<CConnman> g_connman;
|
||||
|
||||
#if ENABLE_ZMQ
|
||||
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
|
||||
|
@ -197,7 +199,10 @@ void Shutdown()
|
|||
if (pwalletMain)
|
||||
pwalletMain->Flush(false);
|
||||
#endif
|
||||
StopNode();
|
||||
MapPort(false);
|
||||
g_connman->Stop();
|
||||
g_connman.reset();
|
||||
|
||||
StopTorControl();
|
||||
UnregisterNodeSignals(GetNodeSignals());
|
||||
|
||||
|
@ -269,11 +274,11 @@ void HandleSIGHUP(int)
|
|||
fReopenDebugLog = true;
|
||||
}
|
||||
|
||||
bool static Bind(const CService &addr, unsigned int flags) {
|
||||
bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {
|
||||
if (!(flags & BF_EXPLICIT) && IsLimited(addr))
|
||||
return false;
|
||||
std::string strError;
|
||||
if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
|
||||
if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
|
||||
if (flags & BF_REPORT_ERROR)
|
||||
return InitError(strError);
|
||||
return false;
|
||||
|
@ -864,7 +869,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
// Make sure enough file descriptors are available
|
||||
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
|
||||
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
|
||||
nMaxConnections = std::max(nUserMaxConnections, 0);
|
||||
int nMaxConnections = std::max(nUserMaxConnections, 0);
|
||||
|
||||
// Trim requested connection counts, to fit into system limitations
|
||||
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
|
||||
|
@ -985,6 +990,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
// Option to startup with mocktime set (used for regression testing):
|
||||
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
|
||||
|
||||
ServiceFlags nLocalServices = NODE_NETWORK;
|
||||
ServiceFlags nRelevantServices = NODE_NETWORK;
|
||||
|
||||
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
|
||||
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
|
||||
|
||||
|
@ -1108,6 +1116,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
#endif // ENABLE_WALLET
|
||||
// ********************************************************* Step 6: network initialization
|
||||
|
||||
assert(!g_connman);
|
||||
g_connman = std::unique_ptr<CConnman>(new CConnman());
|
||||
CConnman& connman = *g_connman;
|
||||
|
||||
RegisterNodeSignals(GetNodeSignals());
|
||||
|
||||
// sanitize comments per BIP-0014, format user agent and check total size
|
||||
|
@ -1145,7 +1157,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
LookupSubNet(net.c_str(), subnet);
|
||||
if (!subnet.IsValid())
|
||||
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
|
||||
CNode::AddWhitelistedRange(subnet);
|
||||
connman.AddWhitelistedRange(subnet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1197,7 +1209,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
CService addrBind;
|
||||
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
|
||||
return InitError(ResolveErrMsg("bind", strBind));
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
|
||||
fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
|
||||
CService addrBind;
|
||||
|
@ -1205,14 +1217,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
return InitError(ResolveErrMsg("whitebind", strBind));
|
||||
if (addrBind.GetPort() == 0)
|
||||
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
|
||||
fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct in_addr inaddr_any;
|
||||
inaddr_any.s_addr = INADDR_ANY;
|
||||
fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
|
||||
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
|
||||
fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE);
|
||||
fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
|
||||
}
|
||||
if (!fBound)
|
||||
return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
|
||||
|
@ -1229,7 +1241,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
}
|
||||
|
||||
BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
|
||||
AddOneShot(strDest);
|
||||
connman.AddOneShot(strDest);
|
||||
|
||||
#if ENABLE_ZMQ
|
||||
pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
|
||||
|
@ -1239,7 +1251,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
}
|
||||
#endif
|
||||
if (mapArgs.count("-maxuploadtarget")) {
|
||||
CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024);
|
||||
connman.SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024);
|
||||
}
|
||||
|
||||
// ********************************************************* Step 7: load block chain
|
||||
|
@ -1505,7 +1517,25 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
|
||||
StartTorControl(threadGroup, scheduler);
|
||||
|
||||
StartNode(threadGroup, scheduler);
|
||||
Discover(threadGroup);
|
||||
|
||||
// Map ports with UPnP
|
||||
MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
|
||||
|
||||
std::string strNodeError;
|
||||
CConnman::Options connOptions;
|
||||
connOptions.nLocalServices = nLocalServices;
|
||||
connOptions.nRelevantServices = nRelevantServices;
|
||||
connOptions.nMaxConnections = nMaxConnections;
|
||||
connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
|
||||
connOptions.nMaxFeeler = 1;
|
||||
connOptions.nBestHeight = chainActive.Height();
|
||||
connOptions.uiInterface = &uiInterface;
|
||||
connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
|
||||
connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
|
||||
|
||||
if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions))
|
||||
return InitError(strNodeError);
|
||||
|
||||
// ********************************************************* Step 12: finished
|
||||
|
||||
|
|
169
src/main.cpp
169
src/main.cpp
|
@ -325,12 +325,6 @@ CNodeState *State(NodeId pnode) {
|
|||
return &it->second;
|
||||
}
|
||||
|
||||
int GetHeight()
|
||||
{
|
||||
LOCK(cs_main);
|
||||
return chainActive.Height();
|
||||
}
|
||||
|
||||
void UpdatePreferredDownload(CNode* node, CNodeState* state)
|
||||
{
|
||||
nPreferredDownload -= state->fPreferredDownload;
|
||||
|
@ -348,7 +342,8 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) {
|
|||
state.address = pnode->addr;
|
||||
}
|
||||
|
||||
void FinalizeNode(NodeId nodeid) {
|
||||
void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
|
||||
fUpdateConnectionTime = false;
|
||||
LOCK(cs_main);
|
||||
CNodeState *state = State(nodeid);
|
||||
|
||||
|
@ -356,7 +351,7 @@ void FinalizeNode(NodeId nodeid) {
|
|||
nSyncStarted--;
|
||||
|
||||
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
|
||||
AddressCurrentlyConnected(state->address);
|
||||
fUpdateConnectionTime = true;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
|
||||
|
@ -469,8 +464,8 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
|
|||
}
|
||||
}
|
||||
|
||||
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) {
|
||||
if (nLocalServices & NODE_WITNESS) {
|
||||
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) {
|
||||
if (pfrom->GetLocalServices() & NODE_WITNESS) {
|
||||
// Don't ever request compact blocks when segwit is enabled.
|
||||
return;
|
||||
}
|
||||
|
@ -483,11 +478,12 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
|
|||
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
|
||||
// As per BIP152, we only get 3 of our peers to announce
|
||||
// blocks using compact encodings.
|
||||
CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front());
|
||||
if (pnodeStop) {
|
||||
bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
|
||||
pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
|
||||
return true;
|
||||
});
|
||||
if(found)
|
||||
lNodesAnnouncingHeaderAndIDs.pop_front();
|
||||
}
|
||||
}
|
||||
fAnnounceUsingCMPCTBLOCK = true;
|
||||
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
|
||||
|
@ -637,7 +633,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
|
|||
|
||||
void RegisterNodeSignals(CNodeSignals& nodeSignals)
|
||||
{
|
||||
nodeSignals.GetHeight.connect(&GetHeight);
|
||||
nodeSignals.ProcessMessages.connect(&ProcessMessages);
|
||||
nodeSignals.SendMessages.connect(&SendMessages);
|
||||
nodeSignals.InitializeNode.connect(&InitializeNode);
|
||||
|
@ -646,7 +641,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals)
|
|||
|
||||
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
|
||||
{
|
||||
nodeSignals.GetHeight.disconnect(&GetHeight);
|
||||
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
|
||||
nodeSignals.SendMessages.disconnect(&SendMessages);
|
||||
nodeSignals.InitializeNode.disconnect(&InitializeNode);
|
||||
|
@ -3016,7 +3010,7 @@ static void NotifyHeaderTip() {
|
|||
* or an activated best chain. pblock is either NULL or a pointer to a block
|
||||
* that is already loaded (to avoid loading it again from disk).
|
||||
*/
|
||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) {
|
||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, CConnman* connman) {
|
||||
CBlockIndex *pindexMostWork = NULL;
|
||||
CBlockIndex *pindexNewTip = NULL;
|
||||
do {
|
||||
|
@ -3056,6 +3050,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|||
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
|
||||
|
||||
// Notifications/callbacks that can run without cs_main
|
||||
if(connman)
|
||||
connman->SetBestHeight(nNewHeight);
|
||||
|
||||
// throw all transactions though the signal-interface
|
||||
// while _not_ holding the cs_main lock
|
||||
|
@ -3088,15 +3084,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|||
int nBlockEstimate = 0;
|
||||
if (fCheckpointsEnabled)
|
||||
nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||
if(connman) {
|
||||
connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) {
|
||||
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
|
||||
BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
|
||||
pnode->PushBlockHash(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Notify external listeners about the new tip.
|
||||
if (!vHashes.empty()) {
|
||||
|
@ -3731,7 +3726,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
|
||||
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman)
|
||||
{
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
@ -3753,7 +3748,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
|
|||
|
||||
NotifyHeaderTip();
|
||||
|
||||
if (!ActivateBestChain(state, chainparams, pblock))
|
||||
if (!ActivateBestChain(state, chainparams, pblock, connman))
|
||||
return error("%s: ActivateBestChain failed", __func__);
|
||||
|
||||
return true;
|
||||
|
@ -4725,9 +4720,47 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
|||
return true;
|
||||
}
|
||||
|
||||
void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams)
|
||||
static void RelayTransaction(const CTransaction& tx, CConnman& connman)
|
||||
{
|
||||
CInv inv(MSG_TX, tx.GetHash());
|
||||
connman.ForEachNode([&inv](CNode* pnode)
|
||||
{
|
||||
pnode->PushInventory(inv);
|
||||
});
|
||||
}
|
||||
|
||||
static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
|
||||
{
|
||||
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
|
||||
|
||||
// Relay to a limited number of other nodes
|
||||
// Use deterministic randomness to send to the same nodes for 24 hours
|
||||
// at a time so the addrKnowns of the chosen nodes prevent repeats
|
||||
static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max());
|
||||
static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max());
|
||||
uint64_t hashAddr = addr.GetHash();
|
||||
std::multimap<uint64_t, CNode*> mapMix;
|
||||
const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
|
||||
|
||||
auto sortfunc = [&mapMix, &hasher](CNode* pnode) {
|
||||
if (pnode->nVersion >= CADDR_TIME_VERSION) {
|
||||
uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
|
||||
mapMix.emplace(hashKey, pnode);
|
||||
}
|
||||
};
|
||||
|
||||
auto pushfunc = [&addr, &mapMix, &nRelayNodes] {
|
||||
for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
|
||||
mi->second->PushAddress(addr);
|
||||
};
|
||||
|
||||
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
|
||||
}
|
||||
|
||||
void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman)
|
||||
{
|
||||
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
|
||||
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
|
||||
|
||||
vector<CInv> vNotFound;
|
||||
|
||||
|
@ -4735,7 +4768,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
|||
|
||||
while (it != pfrom->vRecvGetData.end()) {
|
||||
// Don't bother if send buffer is too full to respond anyway
|
||||
if (pfrom->nSendSize >= SendBufferSize())
|
||||
if (pfrom->nSendSize >= nMaxSendBufferSize)
|
||||
break;
|
||||
|
||||
const CInv &inv = *it;
|
||||
|
@ -4767,7 +4800,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
|||
// disconnect node in case we have reached the outbound limit for serving historical blocks
|
||||
// never disconnect whitelisted nodes
|
||||
static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical
|
||||
if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
|
||||
if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
|
||||
{
|
||||
LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
|
||||
|
||||
|
@ -4891,8 +4924,10 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params
|
|||
return nFetchFlags;
|
||||
}
|
||||
|
||||
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
|
||||
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman)
|
||||
{
|
||||
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
|
||||
|
||||
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
|
||||
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
|
||||
{
|
||||
|
@ -4901,7 +4936,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
}
|
||||
|
||||
|
||||
if (!(nLocalServices & NODE_BLOOM) &&
|
||||
if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
|
||||
(strCommand == NetMsgType::FILTERLOAD ||
|
||||
strCommand == NetMsgType::FILTERADD ||
|
||||
strCommand == NetMsgType::FILTERCLEAR))
|
||||
|
@ -4943,7 +4978,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
pfrom->nServices = ServiceFlags(nServiceInt);
|
||||
if (!pfrom->fInbound)
|
||||
{
|
||||
addrman.SetServices(pfrom->addr, pfrom->nServices);
|
||||
connman.SetServices(pfrom->addr, pfrom->nServices);
|
||||
}
|
||||
if (pfrom->nServicesExpected & ~pfrom->nServices)
|
||||
{
|
||||
|
@ -4984,7 +5019,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
}
|
||||
|
||||
// Disconnect if we connected to ourself
|
||||
if (nNonce == nLocalHostNonce && nNonce > 1)
|
||||
if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
|
||||
{
|
||||
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
|
||||
pfrom->fDisconnect = true;
|
||||
|
@ -5024,7 +5059,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
// Advertise our address
|
||||
if (fListen && !IsInitialBlockDownload())
|
||||
{
|
||||
CAddress addr = GetLocalAddress(&pfrom->addr);
|
||||
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
|
||||
if (addr.IsRoutable())
|
||||
{
|
||||
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
|
||||
|
@ -5037,12 +5072,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
}
|
||||
|
||||
// Get recent addresses
|
||||
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
|
||||
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
|
||||
{
|
||||
pfrom->PushMessage(NetMsgType::GETADDR);
|
||||
pfrom->fGetAddr = true;
|
||||
}
|
||||
addrman.Good(pfrom->addr);
|
||||
connman.MarkAddressGood(pfrom->addr);
|
||||
}
|
||||
|
||||
pfrom->fSuccessfullyConnected = true;
|
||||
|
@ -5107,7 +5142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
vRecv >> vAddr;
|
||||
|
||||
// Don't want addr from older versions unless seeding
|
||||
if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
|
||||
if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)
|
||||
return true;
|
||||
if (vAddr.size() > 1000)
|
||||
{
|
||||
|
@ -5134,32 +5169,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
|
||||
{
|
||||
// Relay to a limited number of other nodes
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
// Use deterministic randomness to send to the same nodes for 24 hours
|
||||
// at a time so the addrKnowns of the chosen nodes prevent repeats
|
||||
static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max());
|
||||
static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max());
|
||||
uint64_t hashAddr = addr.GetHash();
|
||||
multimap<uint64_t, CNode*> mapMix;
|
||||
const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if (pnode->nVersion < CADDR_TIME_VERSION)
|
||||
continue;
|
||||
uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
|
||||
mapMix.insert(make_pair(hashKey, pnode));
|
||||
}
|
||||
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
|
||||
for (multimap<uint64_t, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
|
||||
((*mi).second)->PushAddress(addr);
|
||||
}
|
||||
RelayAddress(addr, fReachable, connman);
|
||||
}
|
||||
// Do not store addresses outside our network
|
||||
if (fReachable)
|
||||
vAddrOk.push_back(addr);
|
||||
}
|
||||
addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
|
||||
connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
|
||||
if (vAddr.size() < 1000)
|
||||
pfrom->fGetAddr = false;
|
||||
if (pfrom->fOneShot)
|
||||
|
@ -5238,7 +5254,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
|
||||
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
|
||||
inv.type |= nFetchFlags;
|
||||
if (nodestate->fProvidesHeaderAndIDs && !(nLocalServices & NODE_WITNESS))
|
||||
if (nodestate->fProvidesHeaderAndIDs && !(pfrom->GetLocalServices() & NODE_WITNESS))
|
||||
vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash));
|
||||
else
|
||||
vToFetch.push_back(inv);
|
||||
|
@ -5261,7 +5277,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
// Track requests for our stuff
|
||||
GetMainSignals().Inventory(inv.hash);
|
||||
|
||||
if (pfrom->nSendSize > (SendBufferSize() * 2)) {
|
||||
if (pfrom->nSendSize > (nMaxSendBufferSize * 2)) {
|
||||
Misbehaving(pfrom->GetId(), 50);
|
||||
return error("send buffer size() = %u", pfrom->nSendSize);
|
||||
}
|
||||
|
@ -5290,7 +5306,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id);
|
||||
|
||||
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
|
||||
ProcessGetData(pfrom, chainparams.GetConsensus());
|
||||
ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5447,7 +5463,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
|
||||
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
|
||||
mempool.check(pcoinsTip);
|
||||
RelayTransaction(tx);
|
||||
RelayTransaction(tx, connman);
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
vWorkQueue.emplace_back(inv.hash, i);
|
||||
}
|
||||
|
@ -5484,7 +5500,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
continue;
|
||||
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
|
||||
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
|
||||
RelayTransaction(orphanTx);
|
||||
RelayTransaction(orphanTx, connman);
|
||||
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
|
||||
vWorkQueue.emplace_back(orphanHash, i);
|
||||
}
|
||||
|
@ -5565,7 +5581,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
int nDoS = 0;
|
||||
if (!state.IsInvalid(nDoS) || nDoS == 0) {
|
||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
|
||||
RelayTransaction(tx);
|
||||
RelayTransaction(tx, connman);
|
||||
} else {
|
||||
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
|
||||
}
|
||||
|
@ -5684,7 +5700,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
txn.blockhash = cmpctblock.header.GetHash();
|
||||
CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
|
||||
blockTxnMsg << txn;
|
||||
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams);
|
||||
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
|
||||
} else {
|
||||
req.blockhash = pindex->GetBlockHash();
|
||||
pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req);
|
||||
|
@ -5705,7 +5721,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
headers.push_back(cmpctblock.header);
|
||||
CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
|
||||
vHeadersMsg << headers;
|
||||
return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams);
|
||||
return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5741,7 +5757,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
pfrom->PushMessage(NetMsgType::GETDATA, invs);
|
||||
} else {
|
||||
CValidationState state;
|
||||
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
|
||||
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, &connman);
|
||||
int nDoS;
|
||||
if (state.IsInvalid(nDoS)) {
|
||||
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
||||
|
@ -5886,10 +5902,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
|
||||
}
|
||||
if (vGetData.size() > 0) {
|
||||
if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) {
|
||||
if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(pfrom->GetLocalServices() & NODE_WITNESS)) {
|
||||
// We seem to be rather well-synced, so it appears pfrom was the first to provide us
|
||||
// with this block! Let's get them to announce using compact blocks in the future.
|
||||
MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom);
|
||||
MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman);
|
||||
// In any case, we want to download using a compact block, not a regular one
|
||||
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
|
||||
}
|
||||
|
@ -5917,7 +5933,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
// Such an unrequested block may still be processed, subject to the
|
||||
// conditions in AcceptBlock().
|
||||
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
|
||||
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
|
||||
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman);
|
||||
int nDoS;
|
||||
if (state.IsInvalid(nDoS)) {
|
||||
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
||||
|
@ -5953,7 +5969,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
pfrom->fSentAddr = true;
|
||||
|
||||
pfrom->vAddrToSend.clear();
|
||||
vector<CAddress> vAddr = addrman.GetAddr();
|
||||
vector<CAddress> vAddr = connman.GetAddresses();
|
||||
BOOST_FOREACH(const CAddress &addr, vAddr)
|
||||
pfrom->PushAddress(addr);
|
||||
}
|
||||
|
@ -5961,14 +5977,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
|
||||
else if (strCommand == NetMsgType::MEMPOOL)
|
||||
{
|
||||
if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted)
|
||||
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
|
||||
{
|
||||
LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
|
||||
pfrom->fDisconnect = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted)
|
||||
if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted)
|
||||
{
|
||||
LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
|
||||
pfrom->fDisconnect = true;
|
||||
|
@ -6167,9 +6183,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
}
|
||||
|
||||
// requires LOCK(cs_vRecvMsg)
|
||||
bool ProcessMessages(CNode* pfrom)
|
||||
bool ProcessMessages(CNode* pfrom, CConnman& connman)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
|
||||
//if (fDebug)
|
||||
// LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
|
||||
|
||||
|
@ -6184,7 +6201,7 @@ bool ProcessMessages(CNode* pfrom)
|
|||
bool fOk = true;
|
||||
|
||||
if (!pfrom->vRecvGetData.empty())
|
||||
ProcessGetData(pfrom, chainparams.GetConsensus());
|
||||
ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
|
||||
|
||||
// this maintains the order of responses
|
||||
if (!pfrom->vRecvGetData.empty()) return fOk;
|
||||
|
@ -6192,7 +6209,7 @@ bool ProcessMessages(CNode* pfrom)
|
|||
std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
|
||||
while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
|
||||
// Don't bother if send buffer is too full to respond anyway
|
||||
if (pfrom->nSendSize >= SendBufferSize())
|
||||
if (pfrom->nSendSize >= nMaxSendBufferSize)
|
||||
break;
|
||||
|
||||
// get next message
|
||||
|
@ -6244,7 +6261,7 @@ bool ProcessMessages(CNode* pfrom)
|
|||
bool fRet = false;
|
||||
try
|
||||
{
|
||||
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams);
|
||||
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman);
|
||||
boost::this_thread::interruption_point();
|
||||
}
|
||||
catch (const std::ios_base::failure& e)
|
||||
|
@ -6309,7 +6326,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
bool SendMessages(CNode* pto)
|
||||
bool SendMessages(CNode* pto, CConnman& connman)
|
||||
{
|
||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||
{
|
||||
|
@ -6396,7 +6413,7 @@ bool SendMessages(CNode* pto)
|
|||
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
|
||||
else
|
||||
{
|
||||
CNode::Ban(pto->addr, BanReasonNodeMisbehaving);
|
||||
connman.Ban(pto->addr, BanReasonNodeMisbehaving);
|
||||
}
|
||||
}
|
||||
state.fShouldBan = false;
|
||||
|
@ -6435,7 +6452,7 @@ bool SendMessages(CNode* pto)
|
|||
// transactions become unconfirmed and spams other nodes.
|
||||
if (!fReindex && !fImporting && !IsInitialBlockDownload())
|
||||
{
|
||||
GetMainSignals().Broadcast(nTimeBestReceived);
|
||||
GetMainSignals().Broadcast(nTimeBestReceived, &connman);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
10
src/main.h
10
src/main.h
|
@ -34,6 +34,7 @@ class CBlockTreeDB;
|
|||
class CBloomFilter;
|
||||
class CChainParams;
|
||||
class CInv;
|
||||
class CConnman;
|
||||
class CScriptCheck;
|
||||
class CTxMemPool;
|
||||
class CValidationInterface;
|
||||
|
@ -222,7 +223,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
|
|||
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
|
||||
* @return True if state.IsValid()
|
||||
*/
|
||||
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
|
||||
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman);
|
||||
/** Check whether enough disk space is available for an incoming block */
|
||||
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
|
||||
/** Open a block file (blk?????.dat) */
|
||||
|
@ -240,13 +241,14 @@ bool LoadBlockIndex();
|
|||
/** Unload database information */
|
||||
void UnloadBlockIndex();
|
||||
/** Process protocol messages received from a given node */
|
||||
bool ProcessMessages(CNode* pfrom);
|
||||
bool ProcessMessages(CNode* pfrom, CConnman& connman);
|
||||
/**
|
||||
* Send queued protocol messages to be sent to a give node.
|
||||
*
|
||||
* @param[in] pto The node which we are sending messages to.
|
||||
* @param[in] connman The connection manager for that node.
|
||||
*/
|
||||
bool SendMessages(CNode* pto);
|
||||
bool SendMessages(CNode* pto, CConnman& connman);
|
||||
/** Run an instance of the script checking thread */
|
||||
void ThreadScriptCheck();
|
||||
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
|
||||
|
@ -262,7 +264,7 @@ std::string GetWarnings(const std::string& strFor);
|
|||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||
bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
|
||||
/** Find the best known block, and make it the tip of the block chain */
|
||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL);
|
||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, CConnman* connman = NULL);
|
||||
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
|
||||
|
||||
/**
|
||||
|
|
807
src/net.cpp
807
src/net.cpp
File diff suppressed because it is too large
Load diff
544
src/net.h
544
src/net.h
|
@ -6,6 +6,8 @@
|
|||
#ifndef BITCOIN_NET_H
|
||||
#define BITCOIN_NET_H
|
||||
|
||||
#include "addrdb.h"
|
||||
#include "addrman.h"
|
||||
#include "amount.h"
|
||||
#include "bloom.h"
|
||||
#include "compat.h"
|
||||
|
@ -20,6 +22,7 @@
|
|||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
|
@ -51,6 +54,8 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
|
|||
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
|
||||
/** Maximum length of strSubVer in `version` message */
|
||||
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
|
||||
/** Maximum number of outgoing nodes */
|
||||
static const int MAX_OUTBOUND_CONNECTIONS = 8;
|
||||
/** -listen default */
|
||||
static const bool DEFAULT_LISTEN = true;
|
||||
/** -upnp default */
|
||||
|
@ -79,25 +84,317 @@ static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
|
|||
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
|
||||
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
|
||||
|
||||
unsigned int ReceiveFloodSize();
|
||||
unsigned int SendBufferSize();
|
||||
|
||||
typedef int NodeId;
|
||||
|
||||
void AddOneShot(const std::string& strDest);
|
||||
void AddressCurrentlyConnected(const CService& addr);
|
||||
CNode* FindNode(const CNetAddr& ip);
|
||||
CNode* FindNode(const CSubNet& subNet);
|
||||
CNode* FindNode(const std::string& addrName);
|
||||
CNode* FindNode(const CService& ip);
|
||||
CNode* FindNode(const NodeId id); //TODO: Remove this
|
||||
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
|
||||
struct AddedNodeInfo
|
||||
{
|
||||
std::string strAddedNode;
|
||||
CService resolvedAddress;
|
||||
bool fConnected;
|
||||
bool fInbound;
|
||||
};
|
||||
|
||||
class CTransaction;
|
||||
class CNodeStats;
|
||||
class CClientUIInterface;
|
||||
|
||||
class CConnman
|
||||
{
|
||||
public:
|
||||
|
||||
enum NumConnections {
|
||||
CONNECTIONS_NONE = 0,
|
||||
CONNECTIONS_IN = (1U << 0),
|
||||
CONNECTIONS_OUT = (1U << 1),
|
||||
CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
|
||||
};
|
||||
|
||||
struct Options
|
||||
{
|
||||
ServiceFlags nLocalServices = NODE_NONE;
|
||||
ServiceFlags nRelevantServices = NODE_NONE;
|
||||
int nMaxConnections = 0;
|
||||
int nMaxOutbound = 0;
|
||||
int nMaxFeeler = 0;
|
||||
int nBestHeight = 0;
|
||||
CClientUIInterface* uiInterface = nullptr;
|
||||
unsigned int nSendBufferMaxSize = 0;
|
||||
unsigned int nReceiveFloodSize = 0;
|
||||
};
|
||||
CConnman();
|
||||
~CConnman();
|
||||
bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options options);
|
||||
void Stop();
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
|
||||
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
|
||||
bool CheckIncomingNonce(uint64_t nonce);
|
||||
|
||||
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
|
||||
|
||||
template<typename Callable>
|
||||
bool ForEachNodeContinueIf(Callable&& func)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (auto&& node : vNodes)
|
||||
if(!func(node))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
template<typename Callable>
|
||||
bool ForEachNodeContinueIf(Callable&& func) const
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (const auto& node : vNodes)
|
||||
if(!func(node))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
template<typename Callable, typename CallableAfter>
|
||||
bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post)
|
||||
{
|
||||
bool ret = true;
|
||||
LOCK(cs_vNodes);
|
||||
for (auto&& node : vNodes)
|
||||
if(!pre(node)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
post();
|
||||
return ret;
|
||||
};
|
||||
|
||||
template<typename Callable, typename CallableAfter>
|
||||
bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post) const
|
||||
{
|
||||
bool ret = true;
|
||||
LOCK(cs_vNodes);
|
||||
for (const auto& node : vNodes)
|
||||
if(!pre(node)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
post();
|
||||
return ret;
|
||||
};
|
||||
|
||||
template<typename Callable>
|
||||
void ForEachNode(Callable&& func)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (auto&& node : vNodes)
|
||||
func(node);
|
||||
};
|
||||
|
||||
template<typename Callable>
|
||||
void ForEachNode(Callable&& func) const
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (const auto& node : vNodes)
|
||||
func(node);
|
||||
};
|
||||
|
||||
template<typename Callable, typename CallableAfter>
|
||||
void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (auto&& node : vNodes)
|
||||
pre(node);
|
||||
post();
|
||||
};
|
||||
|
||||
template<typename Callable, typename CallableAfter>
|
||||
void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (const auto& node : vNodes)
|
||||
pre(node);
|
||||
post();
|
||||
};
|
||||
|
||||
void RelayTransaction(const CTransaction& tx);
|
||||
|
||||
// Addrman functions
|
||||
size_t GetAddressCount() const;
|
||||
void SetServices(const CService &addr, ServiceFlags nServices);
|
||||
void MarkAddressGood(const CAddress& addr);
|
||||
void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
|
||||
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
|
||||
std::vector<CAddress> GetAddresses();
|
||||
void AddressCurrentlyConnected(const CService& addr);
|
||||
|
||||
// Denial-of-service detection/prevention
|
||||
// The idea is to detect peers that are behaving
|
||||
// badly and disconnect/ban them, but do it in a
|
||||
// one-coding-mistake-won't-shatter-the-entire-network
|
||||
// way.
|
||||
// IMPORTANT: There should be nothing I can give a
|
||||
// node that it will forward on that will make that
|
||||
// node's peers drop it. If there is, an attacker
|
||||
// can isolate a node and/or try to split the network.
|
||||
// Dropping a node for sending stuff that is invalid
|
||||
// now but might be valid in a later version is also
|
||||
// dangerous, because it can cause a network split
|
||||
// between nodes running old code and nodes running
|
||||
// new code.
|
||||
void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
|
||||
void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
|
||||
void ClearBanned(); // needed for unit testing
|
||||
bool IsBanned(CNetAddr ip);
|
||||
bool IsBanned(CSubNet subnet);
|
||||
bool Unban(const CNetAddr &ip);
|
||||
bool Unban(const CSubNet &ip);
|
||||
void GetBanned(banmap_t &banmap);
|
||||
void SetBanned(const banmap_t &banmap);
|
||||
|
||||
void AddOneShot(const std::string& strDest);
|
||||
|
||||
bool AddNode(const std::string& node);
|
||||
bool RemoveAddedNode(const std::string& node);
|
||||
std::vector<AddedNodeInfo> GetAddedNodeInfo();
|
||||
|
||||
size_t GetNodeCount(NumConnections num);
|
||||
void GetNodeStats(std::vector<CNodeStats>& vstats);
|
||||
bool DisconnectAddress(const CNetAddr& addr);
|
||||
bool DisconnectNode(const std::string& node);
|
||||
bool DisconnectNode(NodeId id);
|
||||
bool DisconnectSubnet(const CSubNet& subnet);
|
||||
|
||||
unsigned int GetSendBufferSize() const;
|
||||
|
||||
void AddWhitelistedRange(const CSubNet &subnet);
|
||||
|
||||
ServiceFlags GetLocalServices() const;
|
||||
|
||||
//!set the max outbound target in bytes
|
||||
void SetMaxOutboundTarget(uint64_t limit);
|
||||
uint64_t GetMaxOutboundTarget();
|
||||
|
||||
//!set the timeframe for the max outbound target
|
||||
void SetMaxOutboundTimeframe(uint64_t timeframe);
|
||||
uint64_t GetMaxOutboundTimeframe();
|
||||
|
||||
//!check if the outbound target is reached
|
||||
// if param historicalBlockServingLimit is set true, the function will
|
||||
// response true if the limit for serving historical blocks has been reached
|
||||
bool OutboundTargetReached(bool historicalBlockServingLimit);
|
||||
|
||||
//!response the bytes left in the current max outbound cycle
|
||||
// in case of no limit, it will always response 0
|
||||
uint64_t GetOutboundTargetBytesLeft();
|
||||
|
||||
//!response the time in second left in the current max outbound cycle
|
||||
// in case of no limit, it will always response 0
|
||||
uint64_t GetMaxOutboundTimeLeftInCycle();
|
||||
|
||||
uint64_t GetTotalBytesRecv();
|
||||
uint64_t GetTotalBytesSent();
|
||||
|
||||
void SetBestHeight(int height);
|
||||
int GetBestHeight() const;
|
||||
|
||||
|
||||
private:
|
||||
struct ListenSocket {
|
||||
SOCKET socket;
|
||||
bool whitelisted;
|
||||
|
||||
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
|
||||
};
|
||||
|
||||
void ThreadOpenAddedConnections();
|
||||
void ProcessOneShot();
|
||||
void ThreadOpenConnections();
|
||||
void ThreadMessageHandler();
|
||||
void AcceptConnection(const ListenSocket& hListenSocket);
|
||||
void ThreadSocketHandler();
|
||||
void ThreadDNSAddressSeed();
|
||||
|
||||
CNode* FindNode(const CNetAddr& ip);
|
||||
CNode* FindNode(const CSubNet& subNet);
|
||||
CNode* FindNode(const std::string& addrName);
|
||||
CNode* FindNode(const CService& addr);
|
||||
|
||||
bool AttemptToEvictConnection();
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure);
|
||||
bool IsWhitelistedRange(const CNetAddr &addr);
|
||||
|
||||
void DeleteNode(CNode* pnode);
|
||||
|
||||
NodeId GetNewNodeId();
|
||||
|
||||
//!check is the banlist has unwritten changes
|
||||
bool BannedSetIsDirty();
|
||||
//!set the "dirty" flag for the banlist
|
||||
void SetBannedSetDirty(bool dirty=true);
|
||||
//!clean unused entries (if bantime has expired)
|
||||
void SweepBanned();
|
||||
void DumpAddresses();
|
||||
void DumpData();
|
||||
void DumpBanlist();
|
||||
|
||||
unsigned int GetReceiveFloodSize() const;
|
||||
|
||||
// Network stats
|
||||
void RecordBytesRecv(uint64_t bytes);
|
||||
void RecordBytesSent(uint64_t bytes);
|
||||
|
||||
// Network usage totals
|
||||
CCriticalSection cs_totalBytesRecv;
|
||||
CCriticalSection cs_totalBytesSent;
|
||||
uint64_t nTotalBytesRecv;
|
||||
uint64_t nTotalBytesSent;
|
||||
|
||||
// outbound limit & stats
|
||||
uint64_t nMaxOutboundTotalBytesSentInCycle;
|
||||
uint64_t nMaxOutboundCycleStartTime;
|
||||
uint64_t nMaxOutboundLimit;
|
||||
uint64_t nMaxOutboundTimeframe;
|
||||
|
||||
// Whitelisted ranges. Any node connecting from these is automatically
|
||||
// whitelisted (as well as those connecting to whitelisted binds).
|
||||
std::vector<CSubNet> vWhitelistedRange;
|
||||
CCriticalSection cs_vWhitelistedRange;
|
||||
|
||||
unsigned int nSendBufferMaxSize;
|
||||
unsigned int nReceiveFloodSize;
|
||||
|
||||
std::vector<ListenSocket> vhListenSocket;
|
||||
banmap_t setBanned;
|
||||
CCriticalSection cs_setBanned;
|
||||
bool setBannedIsDirty;
|
||||
bool fAddressesInitialized;
|
||||
CAddrMan addrman;
|
||||
std::deque<std::string> vOneShots;
|
||||
CCriticalSection cs_vOneShots;
|
||||
std::vector<std::string> vAddedNodes;
|
||||
CCriticalSection cs_vAddedNodes;
|
||||
std::vector<CNode*> vNodes;
|
||||
std::list<CNode*> vNodesDisconnected;
|
||||
mutable CCriticalSection cs_vNodes;
|
||||
std::atomic<NodeId> nLastNodeId;
|
||||
boost::condition_variable messageHandlerCondition;
|
||||
|
||||
/** Services this instance offers */
|
||||
ServiceFlags nLocalServices;
|
||||
|
||||
/** Services this instance cares about */
|
||||
ServiceFlags nRelevantServices;
|
||||
|
||||
CSemaphore *semOutbound;
|
||||
int nMaxConnections;
|
||||
int nMaxOutbound;
|
||||
int nMaxFeeler;
|
||||
std::atomic<int> nBestHeight;
|
||||
CClientUIInterface* clientInterface;
|
||||
};
|
||||
extern std::unique_ptr<CConnman> g_connman;
|
||||
void Discover(boost::thread_group& threadGroup);
|
||||
void MapPort(bool fUseUPnP);
|
||||
unsigned short GetListenPort();
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
|
||||
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
|
||||
bool StopNode();
|
||||
void SocketSendData(CNode *pnode);
|
||||
size_t SocketSendData(CNode *pnode);
|
||||
|
||||
struct CombinerAll
|
||||
{
|
||||
|
@ -117,11 +414,10 @@ struct CombinerAll
|
|||
// Signals for message handling
|
||||
struct CNodeSignals
|
||||
{
|
||||
boost::signals2::signal<int ()> GetHeight;
|
||||
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
|
||||
boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
|
||||
boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> ProcessMessages;
|
||||
boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> SendMessages;
|
||||
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
|
||||
boost::signals2::signal<void (NodeId)> FinalizeNode;
|
||||
boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;
|
||||
};
|
||||
|
||||
|
||||
|
@ -152,30 +448,15 @@ bool IsLocal(const CService& addr);
|
|||
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
|
||||
bool IsReachable(enum Network net);
|
||||
bool IsReachable(const CNetAddr &addr);
|
||||
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
|
||||
CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
|
||||
|
||||
|
||||
extern bool fDiscover;
|
||||
extern bool fListen;
|
||||
extern ServiceFlags nLocalServices;
|
||||
extern ServiceFlags nRelevantServices;
|
||||
extern bool fRelayTxes;
|
||||
extern uint64_t nLocalHostNonce;
|
||||
extern CAddrMan addrman;
|
||||
|
||||
/** Maximum number of connections to simultaneously allow (aka connection slots) */
|
||||
extern int nMaxConnections;
|
||||
|
||||
extern std::vector<CNode*> vNodes;
|
||||
extern CCriticalSection cs_vNodes;
|
||||
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
|
||||
|
||||
extern std::vector<std::string> vAddedNodes;
|
||||
extern CCriticalSection cs_vAddedNodes;
|
||||
|
||||
extern NodeId nLastNodeId;
|
||||
extern CCriticalSection cs_nLastNodeId;
|
||||
|
||||
/** Subversion as sent to the P2P network in `version` messages */
|
||||
extern std::string strSubVersion;
|
||||
|
||||
|
@ -256,67 +537,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
typedef enum BanReason
|
||||
{
|
||||
BanReasonUnknown = 0,
|
||||
BanReasonNodeMisbehaving = 1,
|
||||
BanReasonManuallyAdded = 2
|
||||
} BanReason;
|
||||
|
||||
class CBanEntry
|
||||
{
|
||||
public:
|
||||
static const int CURRENT_VERSION=1;
|
||||
int nVersion;
|
||||
int64_t nCreateTime;
|
||||
int64_t nBanUntil;
|
||||
uint8_t banReason;
|
||||
|
||||
CBanEntry()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
CBanEntry(int64_t nCreateTimeIn)
|
||||
{
|
||||
SetNull();
|
||||
nCreateTime = nCreateTimeIn;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(this->nVersion);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(nCreateTime);
|
||||
READWRITE(nBanUntil);
|
||||
READWRITE(banReason);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = CBanEntry::CURRENT_VERSION;
|
||||
nCreateTime = 0;
|
||||
nBanUntil = 0;
|
||||
banReason = BanReasonUnknown;
|
||||
}
|
||||
|
||||
std::string banReasonToString()
|
||||
{
|
||||
switch (banReason) {
|
||||
case BanReasonNodeMisbehaving:
|
||||
return "node misbehaving";
|
||||
case BanReasonManuallyAdded:
|
||||
return "manually added";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<CSubNet, CBanEntry> banmap_t;
|
||||
|
||||
/** Information about a peer */
|
||||
class CNode
|
||||
{
|
||||
|
@ -328,6 +548,7 @@ public:
|
|||
CDataStream ssSend;
|
||||
size_t nSendSize; // total size of all vSendMsg entries
|
||||
size_t nSendOffset; // offset inside the first vSendMsg already sent
|
||||
uint64_t nOptimisticBytesWritten;
|
||||
uint64_t nSendBytes;
|
||||
std::deque<CSerializeData> vSendMsg;
|
||||
CCriticalSection cs_vSend;
|
||||
|
@ -374,17 +595,6 @@ public:
|
|||
const uint64_t nKeyedNetGroup;
|
||||
protected:
|
||||
|
||||
// Denial-of-service detection/prevention
|
||||
// Key is IP address, value is banned-until-time
|
||||
static banmap_t setBanned;
|
||||
static CCriticalSection cs_setBanned;
|
||||
static bool setBannedIsDirty;
|
||||
|
||||
// Whitelisted ranges. Any node connecting from these is automatically
|
||||
// whitelisted (as well as those connecting to whitelisted binds).
|
||||
static std::vector<CSubNet> vWhitelistedRange;
|
||||
static CCriticalSection cs_vWhitelistedRange;
|
||||
|
||||
mapMsgCmdSize mapSendBytesPerMsgCmd;
|
||||
mapMsgCmdSize mapRecvBytesPerMsgCmd;
|
||||
|
||||
|
@ -446,33 +656,28 @@ public:
|
|||
CAmount lastSentFeeFilter;
|
||||
int64_t nextSendTimeFeeFilter;
|
||||
|
||||
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
|
||||
CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
|
||||
~CNode();
|
||||
|
||||
private:
|
||||
// Network usage totals
|
||||
static CCriticalSection cs_totalBytesRecv;
|
||||
static CCriticalSection cs_totalBytesSent;
|
||||
static uint64_t nTotalBytesRecv;
|
||||
static uint64_t nTotalBytesSent;
|
||||
|
||||
// outbound limit & stats
|
||||
static uint64_t nMaxOutboundTotalBytesSentInCycle;
|
||||
static uint64_t nMaxOutboundCycleStartTime;
|
||||
static uint64_t nMaxOutboundLimit;
|
||||
static uint64_t nMaxOutboundTimeframe;
|
||||
|
||||
CNode(const CNode&);
|
||||
void operator=(const CNode&);
|
||||
|
||||
static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
|
||||
|
||||
uint64_t nLocalHostNonce;
|
||||
ServiceFlags nLocalServices;
|
||||
int nMyStartingHeight;
|
||||
public:
|
||||
|
||||
NodeId GetId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
uint64_t GetLocalNonce() const {
|
||||
return nLocalHostNonce;
|
||||
}
|
||||
|
||||
int GetRefCount()
|
||||
{
|
||||
assert(nRefCount >= 0);
|
||||
|
@ -489,7 +694,7 @@ public:
|
|||
}
|
||||
|
||||
// requires LOCK(cs_vRecvMsg)
|
||||
bool ReceiveMsgBytes(const char *pch, unsigned int nBytes);
|
||||
bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);
|
||||
|
||||
// requires LOCK(cs_vRecvMsg)
|
||||
void SetRecvVersion(int nVersionIn)
|
||||
|
@ -749,110 +954,19 @@ public:
|
|||
|
||||
void CloseSocketDisconnect();
|
||||
|
||||
// Denial-of-service detection/prevention
|
||||
// The idea is to detect peers that are behaving
|
||||
// badly and disconnect/ban them, but do it in a
|
||||
// one-coding-mistake-won't-shatter-the-entire-network
|
||||
// way.
|
||||
// IMPORTANT: There should be nothing I can give a
|
||||
// node that it will forward on that will make that
|
||||
// node's peers drop it. If there is, an attacker
|
||||
// can isolate a node and/or try to split the network.
|
||||
// Dropping a node for sending stuff that is invalid
|
||||
// now but might be valid in a later version is also
|
||||
// dangerous, because it can cause a network split
|
||||
// between nodes running old code and nodes running
|
||||
// new code.
|
||||
static void ClearBanned(); // needed for unit testing
|
||||
static bool IsBanned(CNetAddr ip);
|
||||
static bool IsBanned(CSubNet subnet);
|
||||
static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
|
||||
static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
|
||||
static bool Unban(const CNetAddr &ip);
|
||||
static bool Unban(const CSubNet &ip);
|
||||
static void GetBanned(banmap_t &banmap);
|
||||
static void SetBanned(const banmap_t &banmap);
|
||||
|
||||
//!check is the banlist has unwritten changes
|
||||
static bool BannedSetIsDirty();
|
||||
//!set the "dirty" flag for the banlist
|
||||
static void SetBannedSetDirty(bool dirty=true);
|
||||
//!clean unused entries (if bantime has expired)
|
||||
static void SweepBanned();
|
||||
|
||||
void copyStats(CNodeStats &stats);
|
||||
|
||||
static bool IsWhitelistedRange(const CNetAddr &ip);
|
||||
static void AddWhitelistedRange(const CSubNet &subnet);
|
||||
|
||||
// Network stats
|
||||
static void RecordBytesRecv(uint64_t bytes);
|
||||
static void RecordBytesSent(uint64_t bytes);
|
||||
|
||||
static uint64_t GetTotalBytesRecv();
|
||||
static uint64_t GetTotalBytesSent();
|
||||
|
||||
//!set the max outbound target in bytes
|
||||
static void SetMaxOutboundTarget(uint64_t limit);
|
||||
static uint64_t GetMaxOutboundTarget();
|
||||
|
||||
//!set the timeframe for the max outbound target
|
||||
static void SetMaxOutboundTimeframe(uint64_t timeframe);
|
||||
static uint64_t GetMaxOutboundTimeframe();
|
||||
|
||||
//!check if the outbound target is reached
|
||||
// if param historicalBlockServingLimit is set true, the function will
|
||||
// response true if the limit for serving historical blocks has been reached
|
||||
static bool OutboundTargetReached(bool historicalBlockServingLimit);
|
||||
|
||||
//!response the bytes left in the current max outbound cycle
|
||||
// in case of no limit, it will always response 0
|
||||
static uint64_t GetOutboundTargetBytesLeft();
|
||||
|
||||
//!response the time in second left in the current max outbound cycle
|
||||
// in case of no limit, it will always response 0
|
||||
static uint64_t GetMaxOutboundTimeLeftInCycle();
|
||||
ServiceFlags GetLocalServices() const
|
||||
{
|
||||
return nLocalServices;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CTransaction;
|
||||
void RelayTransaction(const CTransaction& tx);
|
||||
|
||||
/** Access to the (IP) address database (peers.dat) */
|
||||
class CAddrDB
|
||||
{
|
||||
private:
|
||||
boost::filesystem::path pathAddr;
|
||||
public:
|
||||
CAddrDB();
|
||||
bool Write(const CAddrMan& addr);
|
||||
bool Read(CAddrMan& addr);
|
||||
bool Read(CAddrMan& addr, CDataStream& ssPeers);
|
||||
};
|
||||
|
||||
/** Access to the banlist database (banlist.dat) */
|
||||
class CBanDB
|
||||
{
|
||||
private:
|
||||
boost::filesystem::path pathBanlist;
|
||||
public:
|
||||
CBanDB();
|
||||
bool Write(const banmap_t& banSet);
|
||||
bool Read(banmap_t& banSet);
|
||||
};
|
||||
|
||||
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
|
||||
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
|
||||
|
||||
struct AddedNodeInfo
|
||||
{
|
||||
std::string strAddedNode;
|
||||
CService resolvedAddress;
|
||||
bool fConnected;
|
||||
bool fInbound;
|
||||
};
|
||||
|
||||
std::vector<AddedNodeInfo> GetAddedNodeInfo();
|
||||
|
||||
#endif // BITCOIN_NET_H
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -50,16 +50,18 @@ ClientModel::~ClientModel()
|
|||
|
||||
int ClientModel::getNumConnections(unsigned int flags) const
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
if (flags == CONNECTIONS_ALL) // Shortcut if we want total
|
||||
return vNodes.size();
|
||||
CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;
|
||||
|
||||
int nNum = 0;
|
||||
BOOST_FOREACH(const CNode* pnode, vNodes)
|
||||
if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
|
||||
nNum++;
|
||||
if(flags == CONNECTIONS_IN)
|
||||
connections = CConnman::CONNECTIONS_IN;
|
||||
else if (flags == CONNECTIONS_OUT)
|
||||
connections = CConnman::CONNECTIONS_OUT;
|
||||
else if (flags == CONNECTIONS_ALL)
|
||||
connections = CConnman::CONNECTIONS_ALL;
|
||||
|
||||
return nNum;
|
||||
if(g_connman)
|
||||
return g_connman->GetNodeCount(connections);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ClientModel::getNumBlocks() const
|
||||
|
@ -70,12 +72,16 @@ int ClientModel::getNumBlocks() const
|
|||
|
||||
quint64 ClientModel::getTotalBytesRecv() const
|
||||
{
|
||||
return CNode::GetTotalBytesRecv();
|
||||
if(!g_connman)
|
||||
return 0;
|
||||
return g_connman->GetTotalBytesRecv();
|
||||
}
|
||||
|
||||
quint64 ClientModel::getTotalBytesSent() const
|
||||
{
|
||||
return CNode::GetTotalBytesSent();
|
||||
if(!g_connman)
|
||||
return 0;
|
||||
return g_connman->GetTotalBytesSent();
|
||||
}
|
||||
|
||||
QDateTime ClientModel::getLastBlockDate() const
|
||||
|
|
|
@ -291,17 +291,17 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
|
|||
}
|
||||
}
|
||||
|
||||
QString getEntryData(QAbstractItemView *view, int column, int role)
|
||||
QVariant getEntryData(QAbstractItemView *view, int column, int role)
|
||||
{
|
||||
if(!view || !view->selectionModel())
|
||||
return QString();
|
||||
return QVariant();
|
||||
QModelIndexList selection = view->selectionModel()->selectedRows(column);
|
||||
|
||||
if(!selection.isEmpty()) {
|
||||
// Return first item
|
||||
return (selection.at(0).data(role).toString());
|
||||
return (selection.at(0).data(role));
|
||||
}
|
||||
return QString();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -876,37 +876,34 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point)
|
|||
|
||||
void RPCConsole::disconnectSelectedNode()
|
||||
{
|
||||
if(!g_connman)
|
||||
return;
|
||||
// Get currently selected peer address
|
||||
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
|
||||
NodeId id = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::NetNodeId).toInt();
|
||||
// Find the node, disconnect it and clear the selected node
|
||||
if (CNode *bannedNode = FindNode(strNode.toStdString())) {
|
||||
bannedNode->fDisconnect = true;
|
||||
if(g_connman->DisconnectNode(id))
|
||||
clearSelectedNode();
|
||||
}
|
||||
}
|
||||
|
||||
void RPCConsole::banSelectedNode(int bantime)
|
||||
{
|
||||
if (!clientModel)
|
||||
if (!clientModel || !g_connman)
|
||||
return;
|
||||
|
||||
// Get currently selected peer address
|
||||
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
|
||||
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString();
|
||||
// Find possible nodes, ban it and clear the selected node
|
||||
if (FindNode(strNode.toStdString())) {
|
||||
std::string nStr = strNode.toStdString();
|
||||
std::string addr;
|
||||
int port = 0;
|
||||
SplitHostPort(nStr, port, addr);
|
||||
std::string nStr = strNode.toStdString();
|
||||
std::string addr;
|
||||
int port = 0;
|
||||
SplitHostPort(nStr, port, addr);
|
||||
|
||||
CNetAddr resolved;
|
||||
if(!LookupHost(addr.c_str(), resolved, false))
|
||||
return;
|
||||
CNode::Ban(resolved, BanReasonManuallyAdded, bantime);
|
||||
|
||||
clearSelectedNode();
|
||||
clientModel->getBanTableModel()->refresh();
|
||||
}
|
||||
CNetAddr resolved;
|
||||
if(!LookupHost(addr.c_str(), resolved, false))
|
||||
return;
|
||||
g_connman->Ban(resolved, BanReasonManuallyAdded, bantime);
|
||||
clearSelectedNode();
|
||||
clientModel->getBanTableModel()->refresh();
|
||||
}
|
||||
|
||||
void RPCConsole::unbanSelectedNode()
|
||||
|
@ -915,13 +912,13 @@ void RPCConsole::unbanSelectedNode()
|
|||
return;
|
||||
|
||||
// Get currently selected ban address
|
||||
QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address);
|
||||
QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address).toString();
|
||||
CSubNet possibleSubnet;
|
||||
|
||||
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
|
||||
if (possibleSubnet.IsValid())
|
||||
if (possibleSubnet.IsValid() && g_connman)
|
||||
{
|
||||
CNode::Unban(possibleSubnet);
|
||||
g_connman->Unban(possibleSubnet);
|
||||
clientModel->getBanTableModel()->refresh();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
|||
}
|
||||
|
||||
CReserveKey *keyChange = transaction.getPossibleKeyChange();
|
||||
if(!wallet->CommitTransaction(*newTx, *keyChange))
|
||||
if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get()))
|
||||
return TransactionCommitFailed;
|
||||
|
||||
CTransaction* t = (CTransaction*)newTx;
|
||||
|
|
|
@ -1277,7 +1277,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
|
|||
}
|
||||
|
||||
if (state.IsValid()) {
|
||||
ActivateBestChain(state, Params());
|
||||
ActivateBestChain(state, Params(), NULL, g_connman.get());
|
||||
}
|
||||
|
||||
if (!state.IsValid()) {
|
||||
|
@ -1315,7 +1315,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
|
|||
}
|
||||
|
||||
CValidationState state;
|
||||
ActivateBestChain(state, Params());
|
||||
ActivateBestChain(state, Params(), NULL, g_connman.get());
|
||||
|
||||
if (!state.IsValid()) {
|
||||
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
|
||||
|
|
|
@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
|
|||
continue;
|
||||
}
|
||||
CValidationState state;
|
||||
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
|
||||
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, g_connman.get()))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
||||
++nHeight;
|
||||
blockHashes.push_back(pblock->GetHash().GetHex());
|
||||
|
@ -457,7 +457,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
|||
if (strMode != "template")
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
|
||||
|
||||
if (vNodes.empty())
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
|
||||
|
||||
if (IsInitialBlockDownload())
|
||||
|
@ -754,7 +757,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
|
|||
CValidationState state;
|
||||
submitblock_StateCatcher sc(block.GetHash());
|
||||
RegisterValidationInterface(&sc);
|
||||
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL);
|
||||
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, g_connman.get());
|
||||
UnregisterValidationInterface(&sc);
|
||||
if (fBlockPresent)
|
||||
{
|
||||
|
|
|
@ -89,7 +89,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
|
|||
#endif
|
||||
obj.push_back(Pair("blocks", (int)chainActive.Height()));
|
||||
obj.push_back(Pair("timeoffset", GetTimeOffset()));
|
||||
obj.push_back(Pair("connections", (int)vNodes.size()));
|
||||
if(g_connman)
|
||||
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
|
||||
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
|
||||
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
|
||||
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
|
||||
|
@ -471,14 +472,16 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
|
|||
// atomically with the time change to prevent peers from being
|
||||
// disconnected because we think we haven't communicated with them
|
||||
// in a long time.
|
||||
LOCK2(cs_main, cs_vNodes);
|
||||
LOCK(cs_main);
|
||||
|
||||
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
|
||||
SetMockTime(params[0].get_int64());
|
||||
|
||||
uint64_t t = GetTime();
|
||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||
pnode->nLastSend = pnode->nLastRecv = t;
|
||||
if(g_connman) {
|
||||
g_connman->ForEachNode([t](CNode* pnode) {
|
||||
pnode->nLastSend = pnode->nLastRecv = t;
|
||||
});
|
||||
}
|
||||
|
||||
return NullUniValue;
|
||||
|
|
108
src/rpc/net.cpp
108
src/rpc/net.cpp
|
@ -36,9 +36,10 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("getconnectioncount", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, cs_vNodes);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
return (int)vNodes.size();
|
||||
return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
|
||||
}
|
||||
|
||||
UniValue ping(const UniValue& params, bool fHelp)
|
||||
|
@ -54,29 +55,16 @@ UniValue ping(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("ping", "")
|
||||
);
|
||||
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
// Request that each node send a ping during next message processing pass
|
||||
LOCK2(cs_main, cs_vNodes);
|
||||
|
||||
BOOST_FOREACH(CNode* pNode, vNodes) {
|
||||
pNode->fPingQueued = true;
|
||||
}
|
||||
|
||||
g_connman->ForEachNode([](CNode* pnode) {
|
||||
pnode->fPingQueued = true;
|
||||
});
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
static void CopyNodeStats(std::vector<CNodeStats>& vstats)
|
||||
{
|
||||
vstats.clear();
|
||||
|
||||
LOCK(cs_vNodes);
|
||||
vstats.reserve(vNodes.size());
|
||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||
CNodeStats stats;
|
||||
pnode->copyStats(stats);
|
||||
vstats.push_back(stats);
|
||||
}
|
||||
}
|
||||
|
||||
UniValue getpeerinfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 0)
|
||||
|
@ -127,10 +115,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("getpeerinfo", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
vector<CNodeStats> vstats;
|
||||
CopyNodeStats(vstats);
|
||||
g_connman->GetNodeStats(vstats);
|
||||
|
||||
UniValue ret(UniValue::VARR);
|
||||
|
||||
|
@ -214,32 +203,27 @@ UniValue addnode(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
|
||||
);
|
||||
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
string strNode = params[0].get_str();
|
||||
|
||||
if (strCommand == "onetry")
|
||||
{
|
||||
CAddress addr;
|
||||
OpenNetworkConnection(addr, false, NULL, strNode.c_str());
|
||||
g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
LOCK(cs_vAddedNodes);
|
||||
vector<string>::iterator it = vAddedNodes.begin();
|
||||
for(; it != vAddedNodes.end(); it++)
|
||||
if (strNode == *it)
|
||||
break;
|
||||
|
||||
if (strCommand == "add")
|
||||
{
|
||||
if (it != vAddedNodes.end())
|
||||
if(!g_connman->AddNode(strNode))
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
|
||||
vAddedNodes.push_back(strNode);
|
||||
}
|
||||
else if(strCommand == "remove")
|
||||
{
|
||||
if (it == vAddedNodes.end())
|
||||
if(!g_connman->RemoveAddedNode(strNode))
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
|
||||
vAddedNodes.erase(it);
|
||||
}
|
||||
|
||||
return NullUniValue;
|
||||
|
@ -258,11 +242,12 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
|
||||
);
|
||||
|
||||
CNode* pNode = FindNode(params[0].get_str());
|
||||
if (pNode == NULL)
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
pNode->fDisconnect = true;
|
||||
bool ret = g_connman->DisconnectNode(params[0].get_str());
|
||||
if (!ret)
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
@ -296,7 +281,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
|
||||
);
|
||||
|
||||
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
|
||||
|
||||
if (params.size() == 1) {
|
||||
bool found = false;
|
||||
|
@ -358,19 +346,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleCli("getnettotals", "")
|
||||
+ HelpExampleRpc("getnettotals", "")
|
||||
);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
|
||||
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
|
||||
obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv()));
|
||||
obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent()));
|
||||
obj.push_back(Pair("timemillis", GetTimeMillis()));
|
||||
|
||||
UniValue outboundLimit(UniValue::VOBJ);
|
||||
outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe()));
|
||||
outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget()));
|
||||
outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false)));
|
||||
outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true)));
|
||||
outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft()));
|
||||
outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle()));
|
||||
outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe()));
|
||||
outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget()));
|
||||
outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false)));
|
||||
outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true)));
|
||||
outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft()));
|
||||
outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle()));
|
||||
obj.push_back(Pair("uploadtarget", outboundLimit));
|
||||
return obj;
|
||||
}
|
||||
|
@ -437,15 +427,16 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
|
|||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("version", CLIENT_VERSION));
|
||||
obj.push_back(Pair("subversion", strSubVersion));
|
||||
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
|
||||
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
|
||||
if(g_connman)
|
||||
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
|
||||
obj.push_back(Pair("localrelay", fRelayTxes));
|
||||
obj.push_back(Pair("timeoffset", GetTimeOffset()));
|
||||
obj.push_back(Pair("connections", (int)vNodes.size()));
|
||||
if(g_connman)
|
||||
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
|
||||
obj.push_back(Pair("networks", GetNetworksInfo()));
|
||||
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
|
||||
UniValue localAddresses(UniValue::VARR);
|
||||
|
@ -485,6 +476,8 @@ UniValue setban(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
|
||||
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
|
||||
);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
CSubNet subNet;
|
||||
CNetAddr netAddr;
|
||||
|
@ -506,7 +499,7 @@ UniValue setban(const UniValue& params, bool fHelp)
|
|||
|
||||
if (strCommand == "add")
|
||||
{
|
||||
if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
|
||||
if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
|
||||
|
||||
int64_t banTime = 0; //use standard bantime if not specified
|
||||
|
@ -517,11 +510,11 @@ UniValue setban(const UniValue& params, bool fHelp)
|
|||
if (params.size() == 4 && params[3].isTrue())
|
||||
absolute = true;
|
||||
|
||||
isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
|
||||
isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
|
||||
}
|
||||
else if(strCommand == "remove")
|
||||
{
|
||||
if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
|
||||
if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
|
||||
}
|
||||
return NullUniValue;
|
||||
|
@ -538,8 +531,11 @@ UniValue listbanned(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleRpc("listbanned", "")
|
||||
);
|
||||
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
banmap_t banMap;
|
||||
CNode::GetBanned(banMap);
|
||||
g_connman->GetBanned(banMap);
|
||||
|
||||
UniValue bannedAddresses(UniValue::VARR);
|
||||
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
|
||||
|
@ -567,8 +563,10 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
|
|||
+ HelpExampleCli("clearbanned", "")
|
||||
+ HelpExampleRpc("clearbanned", "")
|
||||
);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
CNode::ClearBanned();
|
||||
g_connman->ClearBanned();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -891,8 +891,14 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
|
|||
} else if (fHaveChain) {
|
||||
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
|
||||
}
|
||||
RelayTransaction(tx);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
CInv inv(MSG_TX, hashTx);
|
||||
g_connman->ForEachNode([&inv](CNode* pnode)
|
||||
{
|
||||
pnode->PushInventory(inv);
|
||||
});
|
||||
return hashTx.GetHex();
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
|
||||
pblock->nNonce = blockinfo[i].nonce;
|
||||
CValidationState state;
|
||||
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
|
||||
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, connman));
|
||||
BOOST_CHECK(state.IsValid());
|
||||
pblock->hashPrevBlock = pblock->GetHash();
|
||||
}
|
||||
|
|
|
@ -153,6 +153,8 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
|
|||
BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
{
|
||||
SOCKET hSocket = INVALID_SOCKET;
|
||||
NodeId id = 0;
|
||||
int height = 0;
|
||||
|
||||
in_addr ipv4Addr;
|
||||
ipv4Addr.s_addr = 0xa0b0c001;
|
||||
|
@ -162,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||
bool fInboundIn = false;
|
||||
|
||||
// Test that fFeeler is false by default.
|
||||
CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
|
||||
CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn);
|
||||
BOOST_CHECK(pnode1->fInbound == false);
|
||||
BOOST_CHECK(pnode1->fFeeler == false);
|
||||
|
||||
fInboundIn = true;
|
||||
CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
|
||||
CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn);
|
||||
BOOST_CHECK(pnode2->fInbound == true);
|
||||
BOOST_CHECK(pnode2->fFeeler == false);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
std::unique_ptr<CConnman> g_connman;
|
||||
|
||||
extern bool fPrintToConsole;
|
||||
extern void noui_connect();
|
||||
|
||||
|
@ -43,6 +45,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
|
|||
BasicTestingSetup::~BasicTestingSetup()
|
||||
{
|
||||
ECC_Stop();
|
||||
g_connman.reset();
|
||||
}
|
||||
|
||||
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
|
||||
|
@ -50,6 +53,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
|||
const CChainParams& chainparams = Params();
|
||||
// Ideally we'd move all the RPC tests to the functional testing framework
|
||||
// instead of unit tests, but for now we need these here.
|
||||
|
||||
RegisterAllCoreRPCCommands(tableRPC);
|
||||
ClearDatadirCache();
|
||||
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
|
||||
|
@ -68,6 +72,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
|||
nScriptCheckThreads = 3;
|
||||
for (int i=0; i < nScriptCheckThreads-1; i++)
|
||||
threadGroup.create_thread(&ThreadScriptCheck);
|
||||
g_connman = std::unique_ptr<CConnman>(new CConnman());
|
||||
connman = g_connman.get();
|
||||
RegisterNodeSignals(GetNodeSignals());
|
||||
}
|
||||
|
||||
|
@ -118,7 +124,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
|
|||
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
|
||||
|
||||
CValidationState state;
|
||||
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
|
||||
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, connman);
|
||||
|
||||
CBlock result = block;
|
||||
delete pblocktemplate;
|
||||
|
|
|
@ -27,10 +27,12 @@ struct BasicTestingSetup {
|
|||
/** Testing setup that configures a complete environment.
|
||||
* Included are data directory, coins database, script check threads setup.
|
||||
*/
|
||||
class CConnman;
|
||||
struct TestingSetup: public BasicTestingSetup {
|
||||
CCoinsViewDB *pcoinsdbview;
|
||||
boost::filesystem::path pathTemp;
|
||||
boost::thread_group threadGroup;
|
||||
CConnman* connman;
|
||||
|
||||
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
|
||||
~TestingSetup();
|
||||
|
|
|
@ -18,7 +18,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
|
||||
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
|
||||
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
|
||||
|
@ -28,7 +28,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||
g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
|
||||
g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
|
||||
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
|
||||
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||
|
|
|
@ -13,6 +13,7 @@ class CBlock;
|
|||
class CBlockIndex;
|
||||
struct CBlockLocator;
|
||||
class CBlockIndex;
|
||||
class CConnman;
|
||||
class CReserveScript;
|
||||
class CTransaction;
|
||||
class CValidationInterface;
|
||||
|
@ -37,7 +38,7 @@ protected:
|
|||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
||||
virtual void UpdatedTransaction(const uint256 &hash) {}
|
||||
virtual void Inventory(const uint256 &hash) {}
|
||||
virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
|
||||
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
|
||||
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
|
||||
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
|
||||
virtual void ResetRequestCount(const uint256 &hash) {};
|
||||
|
@ -58,7 +59,7 @@ struct CMainSignals {
|
|||
/** Notifies listeners about an inventory item being seen on the network. */
|
||||
boost::signals2::signal<void (const uint256 &)> Inventory;
|
||||
/** Tells listeners to broadcast their data. */
|
||||
boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast;
|
||||
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
|
||||
/** Notifies listeners of a block validation result */
|
||||
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
||||
/** Notifies listeners that a key for mining is required (coinbase) */
|
||||
|
|
|
@ -346,6 +346,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
|
|||
if (nValue > curBalance)
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
|
||||
|
||||
if (pwalletMain->GetBroadcastTransactions() && !g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
// Parse Bitcoin address
|
||||
CScript scriptPubKey = GetScriptForDestination(address);
|
||||
|
||||
|
@ -362,7 +365,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
|
|||
strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strError);
|
||||
}
|
||||
if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
|
||||
if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get()))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here.");
|
||||
}
|
||||
|
||||
|
@ -891,6 +894,9 @@ UniValue sendmany(const UniValue& params, bool fHelp)
|
|||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (pwalletMain->GetBroadcastTransactions() && !g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
UniValue sendTo = params[1].get_obj();
|
||||
int nMinDepth = 1;
|
||||
|
@ -953,7 +959,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
|
|||
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
|
||||
if (!fCreated)
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
|
||||
if (!pwalletMain->CommitTransaction(wtx, keyChange))
|
||||
if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get()))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
|
||||
|
||||
return wtx.GetHash().GetHex();
|
||||
|
@ -2308,9 +2314,12 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
|
|||
"Returns array of transaction ids that were re-broadcast.\n"
|
||||
);
|
||||
|
||||
if (!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
|
||||
std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
|
||||
UniValue result(UniValue::VARR);
|
||||
BOOST_FOREACH(const uint256& txid, txids)
|
||||
{
|
||||
|
|
|
@ -1453,15 +1453,21 @@ void CWallet::ReacceptWalletTransactions()
|
|||
}
|
||||
}
|
||||
|
||||
bool CWalletTx::RelayWalletTransaction()
|
||||
bool CWalletTx::RelayWalletTransaction(CConnman* connman)
|
||||
{
|
||||
assert(pwallet->GetBroadcastTransactions());
|
||||
if (!IsCoinBase())
|
||||
{
|
||||
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
|
||||
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
|
||||
RelayTransaction((CTransaction)*this);
|
||||
return true;
|
||||
if (connman) {
|
||||
CInv inv(MSG_TX, GetHash());
|
||||
connman->ForEachNode([&inv](CNode* pnode)
|
||||
{
|
||||
pnode->PushInventory(inv);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -1688,7 +1694,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
|
|||
return CTransaction(tx1) == CTransaction(tx2);
|
||||
}
|
||||
|
||||
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
||||
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)
|
||||
{
|
||||
std::vector<uint256> result;
|
||||
|
||||
|
@ -1706,13 +1712,13 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
|||
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
|
||||
{
|
||||
CWalletTx& wtx = *item.second;
|
||||
if (wtx.RelayWalletTransaction())
|
||||
if (wtx.RelayWalletTransaction(connman))
|
||||
result.push_back(wtx.GetHash());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
|
||||
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
|
||||
{
|
||||
// Do this infrequently and randomly to avoid giving away
|
||||
// that these are our transactions.
|
||||
|
@ -1730,7 +1736,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
|
|||
|
||||
// Rebroadcast unconfirmed txes older than 5 minutes before the last
|
||||
// block was found:
|
||||
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
|
||||
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
|
||||
if (!relayed.empty())
|
||||
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
|
||||
}
|
||||
|
@ -2447,7 +2453,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
|||
/**
|
||||
* Call after CreateTransaction unless you want to abort
|
||||
*/
|
||||
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman)
|
||||
{
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
@ -2481,7 +2487,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
|||
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
|
||||
return false;
|
||||
}
|
||||
wtxNew.RelayWalletTransaction();
|
||||
wtxNew.RelayWalletTransaction(connman);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -401,7 +401,7 @@ public:
|
|||
int64_t GetTxTime() const;
|
||||
int GetRequestCount() const;
|
||||
|
||||
bool RelayWalletTransaction();
|
||||
bool RelayWalletTransaction(CConnman* connman);
|
||||
|
||||
std::set<uint256> GetConflicts() const;
|
||||
};
|
||||
|
@ -748,8 +748,8 @@ public:
|
|||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
|
||||
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
||||
void ReacceptWalletTransactions();
|
||||
void ResendWalletTransactions(int64_t nBestBlockTime);
|
||||
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
|
||||
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman);
|
||||
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
|
||||
CAmount GetBalance() const;
|
||||
CAmount GetUnconfirmedBalance() const;
|
||||
CAmount GetImmatureBalance() const;
|
||||
|
@ -770,7 +770,7 @@ public:
|
|||
*/
|
||||
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
|
||||
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
|
||||
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
|
||||
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman);
|
||||
|
||||
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
|
||||
|
||||
|
|
Loading…
Reference in a new issue