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