Merge pull request #4277 from PastaPastaPasta/backport-more-p2p

Backport more p2p
This commit is contained in:
UdjinM6 2021-07-20 04:05:58 +03:00 committed by GitHub
commit a4f06c90ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 659 additions and 163 deletions

View File

@ -213,6 +213,7 @@ BITCOIN_CORE_H = \
messagesigner.h \
miner.h \
net.h \
net_permissions.h \
net_processing.h \
netaddress.h \
netbase.h \
@ -570,6 +571,7 @@ libdash_common_a_SOURCES = \
keystore.cpp \
netaddress.cpp \
netbase.cpp \
net_permissions.cpp \
policy/feerate.cpp \
protocol.cpp \
saltedhasher.cpp \

View File

@ -239,7 +239,7 @@ void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime
return;
// find a bucket it is in now
int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
int nRnd = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucket = -1;
for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
@ -319,7 +319,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
int nFactor = 1;
for (int n = 0; n < pinfo->nRefCount; n++)
nFactor *= 2;
if (nFactor > 1 && (RandomInt(nFactor) != 0))
if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
return false;
} else {
pinfo = Create(addr, source, &nId);
@ -384,12 +384,12 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
// Use a 50% chance for choosing between tried and new table entries.
if (!newOnly &&
(nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) {
(nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
// use a tried node
double fChanceFactor = 1.0;
while (1) {
int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
while (vvTried[nKBucket][nKBucketPos] == -1) {
nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
@ -397,7 +397,7 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo& info = mapInfo[nId];
if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
}
@ -405,8 +405,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
// use a new node
double fChanceFactor = 1.0;
while (1) {
int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
while (vvNew[nUBucket][nUBucketPos] == -1) {
nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
@ -414,7 +414,7 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo& info = mapInfo[nId];
if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
}
@ -510,7 +510,7 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr)
if (vAddr.size() >= nNodes)
break;
int nRndPos = RandomInt(vRandom.size() - n) + n;
int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
SwapRandom(n, nRndPos);
assert(mapInfo.count(vRandom[n]) == 1);
@ -575,10 +575,6 @@ CAddrInfo CAddrMan::GetAddressInfo_(const CService& addr)
return *pinfo;
}
int CAddrMan::RandomInt(int nMax){
return GetRandInt(nMax);
}
void CAddrMan::ResolveCollisions_()
{
for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
@ -645,7 +641,7 @@ CAddrInfo CAddrMan::SelectTriedCollision_()
std::set<int>::iterator it = m_tried_collisions.begin();
// Selects a random element from m_tried_collisions
std::advance(it, GetRandInt(m_tried_collisions.size()));
std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
int id_new = *it;
// If id_new not found in mapInfo remove it from m_tried_collisions

View File

@ -276,9 +276,6 @@ protected:
//! Return a random to-be-evicted tried table address.
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.
virtual int RandomInt(int nMax);
#ifdef DEBUG_ADDRMAN
//! Perform consistency check. Returns an error code or zero.
int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
@ -575,7 +572,7 @@ public:
{
LOCK(cs);
std::vector<int>().swap(vRandom);
nKey = GetRandHash();
nKey = insecure_rand.rand256();
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
vvNew[bucket][entry] = -1;

View File

@ -67,14 +67,36 @@ void BanMan::ClearBanned()
if (m_client_interface) m_client_interface->BannedListChanged();
}
bool BanMan::IsBanned(CNetAddr net_addr)
int BanMan::IsBannedLevel(CNetAddr net_addr)
{
// Returns the most severe level of banning that applies to this address.
// 0 - Not banned
// 1 - Automatic misbehavior ban
// 2 - Any other ban
int level = 0;
auto current_time = GetTime();
LOCK(m_cs_banned);
for (const auto& it : m_banned) {
CSubNet sub_net = it.first;
CBanEntry ban_entry = it.second;
if (sub_net.Match(net_addr) && GetTime() < ban_entry.nBanUntil) {
if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
if (ban_entry.banReason != BanReasonNodeMisbehaving) return 2;
level = 1;
}
}
return level;
}
bool BanMan::IsBanned(CNetAddr net_addr)
{
auto current_time = GetTime();
LOCK(m_cs_banned);
for (const auto& it : m_banned) {
CSubNet sub_net = it.first;
CBanEntry ban_entry = it.second;
if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
return true;
}
}
@ -83,11 +105,12 @@ bool BanMan::IsBanned(CNetAddr net_addr)
bool BanMan::IsBanned(CSubNet sub_net)
{
auto current_time = GetTime();
LOCK(m_cs_banned);
banmap_t::iterator i = m_banned.find(sub_net);
if (i != m_banned.end()) {
CBanEntry ban_entry = (*i).second;
if (GetTime() < ban_entry.nBanUntil) {
if (current_time < ban_entry.nBanUntil) {
return true;
}
}

View File

@ -42,6 +42,7 @@ public:
void Ban(const CNetAddr& net_addr, const BanReason& ban_reason, int64_t ban_time_offset = 0, bool since_unix_epoch = false);
void Ban(const CSubNet& sub_net, const BanReason& ban_reason, int64_t ban_time_offset = 0, bool since_unix_epoch = false);
void ClearBanned();
int IsBannedLevel(CNetAddr net_addr);
bool IsBanned(CNetAddr net_addr);
bool IsBanned(CSubNet sub_net);
bool Unban(const CNetAddr& net_addr);

View File

@ -30,6 +30,7 @@
#include <miner.h>
#include <netbase.h>
#include <net.h>
#include <net_permissions.h>
#include <net_processing.h>
#include <policy/feerate.h>
#include <policy/fees.h>
@ -2526,21 +2527,16 @@ bool AppInitMain()
connOptions.vBinds.push_back(addrBind);
}
for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
return InitError(ResolveErrMsg("whitebind", strBind));
}
if (addrBind.GetPort() == 0) {
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
}
connOptions.vWhiteBinds.push_back(addrBind);
NetWhitebindPermissions whitebind;
std::string error;
if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error);
connOptions.vWhiteBinds.push_back(whitebind);
}
for (const auto& net : gArgs.GetArgs("-whitelist")) {
CSubNet subnet;
LookupSubNet(net.c_str(), subnet);
if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
NetWhitelistPermissions subnet;
std::string error;
if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(error);
connOptions.vWhitelistedRange.push_back(subnet);
}

View File

@ -181,7 +181,7 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
// NORMAL NETWORK MODE - TESTNET/MAINNET
{
if ((pnode->fWhitelisted || pnode->m_manual_connection) && !netfulfilledman.HasFulfilledRequest(pnode->addr, strAllow)) {
if ((pnode->HasPermission(PF_NOBAN) || pnode->m_manual_connection) && !netfulfilledman.HasFulfilledRequest(pnode->addr, strAllow)) {
netfulfilledman.RemoveAllFulfilledRequests(pnode->addr);
netfulfilledman.AddFulfilledRequest(pnode->addr, strAllow);
LogPrintf("CMasternodeSync::ProcessTick -- skipping mnsync restrictions for peer=%d\n", pnode->GetId());

View File

@ -17,6 +17,7 @@
#include <consensus/consensus.h>
#include <crypto/common.h>
#include <crypto/sha256.h>
#include <net_permissions.h>
#include <primitives/transaction.h>
#include <netbase.h>
#include <scheduler.h>
@ -98,7 +99,6 @@ enum BindFlags {
BF_NONE = 0,
BF_EXPLICIT = (1U << 0),
BF_REPORT_ERROR = (1U << 1),
BF_WHITELIST = (1U << 2),
};
#ifndef USE_WAKEUP_PIPE
@ -176,11 +176,12 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
const int64_t nOneWeek = 7*24*60*60;
std::vector<CAddress> vSeedsOut;
vSeedsOut.reserve(vSeedsIn.size());
FastRandomContext rng;
for (const auto& seed_in : vSeedsIn) {
struct in6_addr ip;
memcpy(&ip, seed_in.addr, sizeof(ip));
CAddress addr(CService(ip, seed_in.port), GetDesirableServiceFlags(NODE_NONE));
addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek;
vSeedsOut.push_back(addr);
}
return vSeedsOut;
@ -230,16 +231,16 @@ void AdvertiseLocal(CNode *pnode)
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
FastRandomContext rng;
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))
{
addrLocal.SetIP(pnode->GetAddrLocal());
}
if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
{
LogPrint(BCLog::NET, "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
FastRandomContext insecure_rand;
pnode->PushAddress(addrLocal, insecure_rand);
pnode->PushAddress(addrLocal, rng);
}
}
}
@ -539,12 +540,10 @@ void CNode::CloseSocketDisconnect(CConnman* connman)
statsClient.inc("peers.disconnect", 1.0f);
}
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
for (const CSubNet& subnet : vWhitelistedRange) {
if (subnet.Match(addr))
return true;
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
for (const auto& subnet : vWhitelistedRange) {
if (subnet.m_subnet.Match(addr)) NetPermissions::AddFlag(flags, subnet.m_flags);
}
return false;
}
std::string CNode::GetAddrName() const {
@ -614,7 +613,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
X(mapRecvBytesPerMsgCmd);
X(nRecvBytes);
}
X(fWhitelisted);
X(m_legacyWhitelisted);
X(m_permissionFlags);
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
@ -848,6 +848,7 @@ struct NodeEvictionCandidate
bool fRelayTxes;
bool fBloomFilter;
uint64_t nKeyedNetGroup;
bool prefer_evict;
};
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate& a, const NodeEvictionCandidate& b)
@ -906,7 +907,7 @@ bool CConnman::AttemptToEvictConnection()
LOCK(cs_vNodes);
for (const CNode* node : vNodes) {
if (node->fWhitelisted)
if (node->HasPermission(PF_NOBAN))
continue;
if (!node->fInbound)
continue;
@ -935,7 +936,8 @@ bool CConnman::AttemptToEvictConnection()
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
node->nLastBlockTime, node->nLastTXTime,
HasAllDesirableServiceFlags(node->nServices),
node->fRelayTxes, node->pfilter != nullptr, node->nKeyedNetGroup};
node->fRelayTxes, node->pfilter != nullptr, node->nKeyedNetGroup,
node->m_prefer_evict};
vEvictionCandidates.push_back(candidate);
}
}
@ -960,6 +962,14 @@ bool CConnman::AttemptToEvictConnection()
if (vEvictionCandidates.empty()) return false;
// If any remaining peers are preferred for eviction consider only them.
// This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
// then we probably don't want to evict it no matter what.
if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
[](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
}
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
uint64_t naMostConnections;
@ -1008,7 +1018,19 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
}
}
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
NetPermissionFlags permissionFlags = NetPermissionFlags::PF_NONE;
hListenSocket.AddSocketPermissionFlags(permissionFlags);
AddWhitelistPermissionFlags(permissionFlags, addr);
bool legacyWhitelisted = false;
if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_ISIMPLICIT)) {
NetPermissions::ClearFlag(permissionFlags, PF_ISIMPLICIT);
if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY);
if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permissionFlags, PF_RELAY);
NetPermissions::AddFlag(permissionFlags, PF_MEMPOOL);
NetPermissions::AddFlag(permissionFlags, PF_NOBAN);
legacyWhitelisted = true;
}
{
LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) {
@ -1054,7 +1076,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
// on all platforms. Set it again here just to be sure.
SetSocketNoDelay(hSocket);
if (m_banman && m_banman->IsBanned(addr) && !whitelisted)
int bannedlevel = m_banman ? m_banman->IsBannedLevel(addr) : 0;
// Don't accept connections from banned peers, but if our inbound slots aren't almost full, accept
// if the only banning reason was an automatic misbehavior ban.
if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_NOBAN) && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
{
LogPrint(BCLog::NET, "%s (banned)\n", strDropped);
CloseSocket(hSocket);
@ -1088,9 +1114,16 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
CAddress addr_bind = GetBindAddress(hSocket);
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
ServiceFlags nodeServices = nLocalServices;
if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) {
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
}
CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
pnode->m_permissionFlags = permissionFlags;
// If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility)
pnode->m_legacyWhitelisted = legacyWhitelisted;
pnode->m_prefer_evict = bannedlevel > 0;
m_msgproc->InitializeNode(pnode);
if (fLogIPs) {
@ -2687,7 +2720,7 @@ void CConnman::ThreadMessageHandler()
bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, NetPermissionFlags permissions)
{
strError = "";
int nOne = 1;
@ -2775,9 +2808,9 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
}
#endif
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
vhListenSocket.push_back(ListenSocket(hListenSocket, permissions));
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
if (addrBind.IsRoutable() && fDiscover && (permissions & PF_NOBAN) == 0)
AddLocal(addrBind, LOCAL_BIND);
return true;
@ -2874,11 +2907,11 @@ NodeId CConnman::GetNewNodeId()
}
bool CConnman::Bind(const CService &addr, unsigned int flags) {
bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags permissions) {
if (!(flags & BF_EXPLICIT) && !IsReachable(addr))
return false;
std::string strError;
if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
if (!BindListenPort(addr, strError, permissions)) {
if ((flags & BF_REPORT_ERROR) && clientInterface) {
clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
}
@ -2887,20 +2920,21 @@ bool CConnman::Bind(const CService &addr, unsigned int flags) {
return true;
}
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds) {
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds)
{
bool fBound = false;
for (const auto& addrBind : binds) {
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR), NetPermissionFlags::PF_NONE);
}
for (const auto& addrBind : whiteBinds) {
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
fBound |= Bind(addrBind.m_service, (BF_EXPLICIT | BF_REPORT_ERROR), addrBind.m_flags);
}
if (binds.empty() && whiteBinds.empty()) {
struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY;
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE);
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::PF_NONE);
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::PF_NONE);
}
return fBound;
}
@ -3702,7 +3736,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nVersion = 0;
nNumWarningsSkipped = 0;
nLastWarningTime = 0;
fWhitelisted = false;
fOneShot = false;
m_manual_connection = false;
fClient = false; // set by version message

View File

@ -15,6 +15,7 @@
#include <hash.h>
#include <limitedmap.h>
#include <netaddress.h>
#include <net_permissions.h>
#include <policy/feerate.h>
#include <protocol.h>
#include <random.h>
@ -48,6 +49,11 @@ class CScheduler;
class CNode;
class BanMan;
/** Default for -whitelistrelay. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for -whitelistforcerelay. */
static const bool DEFAULT_WHITELISTFORCERELAY = false;
/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
static const int PING_INTERVAL = 2 * 60;
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
@ -171,8 +177,9 @@ public:
uint64_t nMaxOutboundLimit = 0;
int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT;
std::vector<std::string> vSeedNodes;
std::vector<CSubNet> vWhitelistedRange;
std::vector<CService> vBinds, vWhiteBinds;
std::vector<NetWhitelistPermissions> vWhitelistedRange;
std::vector<NetWhitebindPermissions> vWhiteBinds;
std::vector<CService> vBinds;
bool m_use_addrman_outgoing = true;
std::vector<std::string> m_specified_outgoing;
std::vector<std::string> m_added_nodes;
@ -210,7 +217,18 @@ public:
CConnman(uint64_t seed0, uint64_t seed1);
~CConnman();
bool Start(CScheduler& scheduler, const Options& options);
void Stop();
// TODO: Remove NO_THREAD_SAFETY_ANALYSIS. Lock cs_vNodes before reading the variable vNodes.
//
// When removing NO_THREAD_SAFETY_ANALYSIS be aware of the following lock order requirements:
// * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling GetExtraOutboundCount
// which locks cs_vNodes.
// * ProcessMessage locks cs_main and g_cs_orphans before indirectly calling ForEachNode which
// locks cs_vNodes.
//
// Thus the implicit locking order requirement is: (1) cs_main, (2) g_cs_orphans, (3) cs_vNodes.
void Stop() NO_THREAD_SAFETY_ANALYSIS;
void Interrupt();
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
@ -461,15 +479,17 @@ public:
private:
struct ListenSocket {
public:
SOCKET socket;
bool whitelisted;
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); }
ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {}
private:
NetPermissionFlags m_permissions;
};
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
bool Bind(const CService &addr, unsigned int flags);
bool InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds);
bool BindListenPort(const CService& bindAddr, std::string& strError, NetPermissionFlags permissions);
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds);
void ThreadOpenAddedConnections();
void AddOneShot(const std::string& strDest);
void ProcessOneShot();
@ -506,7 +526,7 @@ private:
bool AttemptToEvictConnection();
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = nullptr, bool fCountFailure = false, bool manual_connection = false);
bool IsWhitelistedRange(const CNetAddr &addr);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
void DeleteNode(CNode* pnode);
@ -543,7 +563,7 @@ private:
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
std::vector<CSubNet> vWhitelistedRange;
std::vector<NetWhitelistPermissions> vWhitelistedRange;
unsigned int nSendBufferMaxSize;
unsigned int nReceiveFloodSize;
@ -561,7 +581,7 @@ private:
std::map<std::pair<Consensus::LLMQType, uint256>, std::set<uint256>> masternodeQuorumRelayMembers; // protected by cs_vPendingMasternodes
std::set<uint256> masternodePendingProbes;
mutable CCriticalSection cs_vPendingMasternodes;
std::vector<CNode*> vNodes;
std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
std::list<CNode*> vNodesDisconnected;
std::unordered_map<SOCKET, CNode*> mapSocketToNode;
mutable CCriticalSection cs_vNodes;
@ -639,7 +659,6 @@ void StartMapPort();
void InterruptMapPort();
void StopMapPort();
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
struct CombinerAll
{
@ -744,7 +763,8 @@ public:
mapMsgCmdSize mapSendBytesPerMsgCmd;
uint64_t nRecvBytes;
mapMsgCmdSize mapRecvBytesPerMsgCmd;
bool fWhitelisted;
NetPermissionFlags m_permissionFlags;
bool m_legacyWhitelisted;
double dPingTime;
double dPingWait;
double dMinPing;
@ -855,7 +875,12 @@ public:
*/
std::string cleanSubVer GUARDED_BY(cs_SubVer){};
CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer
bool fWhitelisted; // This peer can bypass DoS banning.
bool m_prefer_evict{false}; // This peer is preferred for eviction.
bool HasPermission(NetPermissionFlags permission) const {
return NetPermissions::HasFlag(m_permissionFlags, permission);
}
// This boolean is unusued in actual processing, only present for backward compatibility at RPC/QT level
bool m_legacyWhitelisted{false};
bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool m_manual_connection;
@ -981,6 +1006,7 @@ private:
const ServiceFlags nLocalServices;
const int nMyStartingHeight;
int nSendVersion;
NetPermissionFlags m_permissionFlags{ PF_NONE };
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
mutable CCriticalSection cs_addrName;

105
src/net_permissions.cpp Normal file
View File

@ -0,0 +1,105 @@
// Copyright (c) 2009-2018 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 <net_permissions.h>
#include <util/system.h>
#include <netbase.h>
// The parse the following format "perm1,perm2@xxxxxx"
bool TryParsePermissionFlags(const std::string str, NetPermissionFlags& output, size_t& readen, std::string& error)
{
NetPermissionFlags flags = PF_NONE;
const auto atSeparator = str.find('@');
// if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
if (atSeparator == std::string::npos) {
NetPermissions::AddFlag(flags, PF_ISIMPLICIT);
readen = 0;
}
// else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
else {
readen = 0;
// permissions == perm1,perm2
const auto permissions = str.substr(0, atSeparator);
while (readen < permissions.length()) {
const auto commaSeparator = permissions.find(',', readen);
const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
// permission == perm1
const auto permission = permissions.substr(readen, len);
readen += len; // We read "perm1"
if (commaSeparator != std::string::npos) readen++; // We read ","
if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, PF_BLOOMFILTER);
else if (permission == "noban") NetPermissions::AddFlag(flags, PF_NOBAN);
else if (permission == "forcerelay") NetPermissions::AddFlag(flags, PF_FORCERELAY);
else if (permission == "mempool") NetPermissions::AddFlag(flags, PF_MEMPOOL);
else if (permission == "all") NetPermissions::AddFlag(flags, PF_ALL);
else if (permission == "relay") NetPermissions::AddFlag(flags, PF_RELAY);
else if (permission.length() == 0); // Allow empty entries
else {
error = strprintf(_("Invalid P2P permission: '%s'"), permission);
return false;
}
}
readen++;
}
output = flags;
error = "";
return true;
}
std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
{
std::vector<std::string> strings;
if (NetPermissions::HasFlag(flags, PF_BLOOMFILTER)) strings.push_back("bloomfilter");
if (NetPermissions::HasFlag(flags, PF_NOBAN)) strings.push_back("noban");
if (NetPermissions::HasFlag(flags, PF_FORCERELAY)) strings.push_back("forcerelay");
if (NetPermissions::HasFlag(flags, PF_RELAY)) strings.push_back("relay");
if (NetPermissions::HasFlag(flags, PF_MEMPOOL)) strings.push_back("mempool");
return strings;
}
bool NetWhitebindPermissions::TryParse(const std::string str, NetWhitebindPermissions& output, std::string& error)
{
NetPermissionFlags flags;
size_t offset;
if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
const std::string strBind = str.substr(offset);
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
error = strprintf(_("Cannot resolve -%s address: '%s'"), "whitebind", strBind);
return false;
}
if (addrBind.GetPort() == 0) {
error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
return false;
}
output.m_flags = flags;
output.m_service = addrBind;
error = "";
return true;
}
bool NetWhitelistPermissions::TryParse(const std::string str, NetWhitelistPermissions& output, std::string& error)
{
NetPermissionFlags flags;
size_t offset;
if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
const std::string net = str.substr(offset);
CSubNet subnet;
LookupSubNet(net.c_str(), subnet);
if (!subnet.IsValid()) {
error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
return false;
}
output.m_flags = flags;
output.m_subnet = subnet;
error = "";
return true;
}

62
src/net_permissions.h Normal file
View File

@ -0,0 +1,62 @@
// Copyright (c) 2009-2018 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 <string>
#include <vector>
#include <netaddress.h>
#ifndef BITCOIN_NET_PERMISSIONS_H
#define BITCOIN_NET_PERMISSIONS_H
enum NetPermissionFlags
{
PF_NONE = 0,
// Can query bloomfilter even if -peerbloomfilters is false
PF_BLOOMFILTER = (1U << 1),
// Relay and accept transactions from this peer, even if -blocksonly is true
PF_RELAY = (1U << 3),
// Always relay transactions from this peer, even if already in mempool or rejected from policy
// Keep parameter interaction: forcerelay implies relay
PF_FORCERELAY = (1U << 2) | PF_RELAY,
// Can't be banned for misbehavior
PF_NOBAN = (1U << 4),
// Can query the mempool
PF_MEMPOOL = (1U << 5),
// True if the user did not specifically set fine grained permissions
PF_ISIMPLICIT = (1U << 31),
PF_ALL = PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY | PF_NOBAN | PF_MEMPOOL,
};
class NetPermissions
{
public:
NetPermissionFlags m_flags;
static std::vector<std::string> ToStrings(NetPermissionFlags flags);
static inline bool HasFlag(const NetPermissionFlags& flags, NetPermissionFlags f)
{
return (flags & f) == f;
}
static inline void AddFlag(NetPermissionFlags& flags, NetPermissionFlags f)
{
flags = static_cast<NetPermissionFlags>(flags | f);
}
static inline void ClearFlag(NetPermissionFlags& flags, NetPermissionFlags f)
{
flags = static_cast<NetPermissionFlags>(flags & ~f);
}
};
class NetWhitebindPermissions : public NetPermissions
{
public:
static bool TryParse(const std::string str, NetWhitebindPermissions& output, std::string& error);
CService m_service;
};
class NetWhitelistPermissions : public NetPermissions
{
public:
static bool TryParse(const std::string str, NetWhitelistPermissions& output, std::string& error);
CSubNet m_subnet;
};
#endif // BITCOIN_NET_PERMISSIONS_H

View File

@ -114,6 +114,7 @@ struct COrphanTx {
CTransactionRef tx;
NodeId fromPeer;
int64_t nTimeExpire;
size_t list_pos;
size_t nTxSize;
};
CCriticalSection g_cs_orphans;
@ -213,6 +214,8 @@ namespace {
};
std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans);
std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans); //! For random eviction
static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0;
static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans);
} // namespace
@ -415,7 +418,7 @@ static void UpdatePreferredDownload(CNode* node, CNodeState* state) EXCLUSIVE_LO
nPreferredDownload -= state->fPreferredDownload;
// Whether this node should be marked as a preferred download node.
state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
state->fPreferredDownload = (!node->fInbound || node->HasPermission(PF_NOBAN)) && !node->fOneShot && !node->fClient;
nPreferredDownload += state->fPreferredDownload;
}
@ -956,8 +959,9 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE
return false;
}
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME, sz});
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME, g_orphan_list.size(), sz});
assert(ret.second);
g_orphan_list.push_back(ret.first);
for (const CTxIn& txin : tx->vin) {
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
}
@ -987,6 +991,18 @@ int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
if (itPrev->second.empty())
mapOrphanTransactionsByPrev.erase(itPrev);
}
size_t old_pos = it->second.list_pos;
assert(g_orphan_list[old_pos] == it);
if (old_pos + 1 != g_orphan_list.size()) {
// Unless we're deleting the last entry in g_orphan_list, move the last
// entry to the position we're deleting.
auto it_last = g_orphan_list.back();
g_orphan_list[old_pos] = it_last;
it_last->second.list_pos = old_pos;
}
g_orphan_list.pop_back();
assert(nMapOrphanTransactionsSize >= it->second.nTxSize);
nMapOrphanTransactionsSize -= it->second.nTxSize;
mapOrphanTransactions.erase(it);
@ -1037,14 +1053,12 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphansSize)
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL;
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased);
}
FastRandomContext rng;
while (!mapOrphanTransactions.empty() && nMapOrphanTransactionsSize > nMaxOrphansSize)
{
// Evict a random orphan:
uint256 randomhash = GetRandHash();
std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
size_t randompos = rng.randrange(g_orphan_list.size());
EraseOrphanTx(g_orphan_list[randompos]->first);
++nEvicted;
}
return nEvicted;
@ -1481,7 +1495,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
// disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes
if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->HasPermission(PF_NOBAN))
{
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
@ -1490,7 +1504,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
send = false;
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
if (send && !pfrom->fWhitelisted && (
if (send && !pfrom->HasPermission(PF_NOBAN) && (
(((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
@ -2535,7 +2549,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
bool fBlocksOnly = !fRelayTxes;
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
if (pfrom->HasPermission(PF_RELAY))
fBlocksOnly = false;
LOCK(cs_main);
@ -2758,7 +2772,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
LOCK(cs_main);
if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
if (IsInitialBlockDownload() && !pfrom->HasPermission(PF_NOBAN)) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
return true;
}
@ -2816,7 +2830,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (strCommand == NetMsgType::TX || strCommand == NetMsgType::DSTX || strCommand == NetMsgType::LEGACYTXLOCKREQUEST) {
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
if (!fRelayTxes && !pfrom->HasPermission(PF_RELAY))
{
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());
return true;
@ -2975,7 +2989,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
}
if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
if (pfrom->HasPermission(PF_FORCERELAY)) {
// Always relay transactions received from whitelisted peers, even
// if they were already in the mempool or rejected from it due
// to policy, allowing the node to function as a gateway for
@ -3408,17 +3422,23 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (strCommand == NetMsgType::MEMPOOL) {
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->HasPermission(PF_MEMPOOL))
{
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
if (!pfrom->HasPermission(PF_NOBAN))
{
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
}
return true;
}
if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted)
if (connman->OutboundTargetReached(false) && !pfrom->HasPermission(PF_MEMPOOL))
{
LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
if (!pfrom->HasPermission(PF_NOBAN))
{
LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
}
return true;
}
@ -3659,7 +3679,7 @@ bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_
if (state.fShouldBan) {
state.fShouldBan = false;
if (pnode->fWhitelisted)
if (pnode->HasPermission(PF_NOBAN))
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->GetLogString());
else if (pnode->m_manual_connection)
LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->GetLogString());
@ -4255,7 +4275,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Check whether periodic sends should happen
// Note: If this node is running in a Masternode mode, it makes no sense to delay outgoing txes
// because we never produce any txes ourselves i.e. no privacy is lost in this case.
bool fSendTrickle = pto->fWhitelisted || fMasternodeMode;
bool fSendTrickle = pto->HasPermission(PF_NOBAN) || fMasternodeMode;
if (pto->nNextInvSend < current_time) {
fSendTrickle = true;
if (pto->fInbound) {
@ -4419,7 +4439,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Note: If all our peers are inbound, then we won't
// disconnect our sync peer for stalling; we have bigger
// problems if we can't get any outbound peers.
if (!pto->fWhitelisted) {
if (!pto->HasPermission(PF_NOBAN)) {
LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId());
pto->fDisconnect = true;
return true;

View File

@ -20,6 +20,7 @@ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE = 10; // this all
static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
/** Default for BIP61 (sending reject messages) */
static constexpr bool DEFAULT_ENABLE_BIP61 = true;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
private:

View File

@ -1246,7 +1246,7 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No"));
ui->peerWhitelisted->setText(stats->nodeStats.m_legacyWhitelisted ? tr("Yes") : tr("No"));
auto dmn = clientModel->getMasternodeList().GetMNByService(stats->nodeStats.addr);
if (dmn == nullptr) {
ui->peerNodeType->setText(tr("Regular"));

View File

@ -430,6 +430,7 @@ uint256 FastRandomContext::rand256()
std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
{
if (requires_seed) RandomSeed();
std::vector<unsigned char> ret(len);
if (len > 0) {
rng.Keystream(&ret[0], len);
@ -495,6 +496,20 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete
rng.SetKey(seed.begin(), 32);
}
FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept
{
requires_seed = from.requires_seed;
rng = from.rng;
std::copy(std::begin(from.bytebuf), std::end(from.bytebuf), std::begin(bytebuf));
bytebuf_size = from.bytebuf_size;
bitbuf = from.bitbuf;
bitbuf_size = from.bitbuf_size;
from.requires_seed = true;
from.bytebuf_size = 0;
from.bitbuf_size = 0;
return *this;
}
void RandomInit()
{
RDRandInit();

View File

@ -80,6 +80,14 @@ public:
/** Initialize with explicit seed (only for testing) */
explicit FastRandomContext(const uint256& seed);
// Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded).
FastRandomContext(const FastRandomContext&) = delete;
FastRandomContext(FastRandomContext&&) = delete;
FastRandomContext& operator=(const FastRandomContext&) = delete;
/** Move a FastRandomContext. If the original one is used again, it will be reseeded. */
FastRandomContext& operator=(FastRandomContext&& from) noexcept;
/** Generate a random 64-bit integer. */
uint64_t rand64()
{

View File

@ -12,6 +12,7 @@
#include <validation.h>
#include <net.h>
#include <net_processing.h>
#include <net_permissions.h>
#include <netbase.h>
#include <policy/policy.h>
#include <rpc/protocol.h>
@ -188,7 +189,12 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
}
obj.pushKV("inflight", heights);
}
obj.pushKV("whitelisted", stats.fWhitelisted);
obj.pushKV("whitelisted", stats.m_legacyWhitelisted);
UniValue permissions(UniValue::VARR);
for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
permissions.push_back(permission);
}
obj.pushKV("permissions", permissions);
UniValue sendPerMsgCmd(UniValue::VOBJ);
for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) {

View File

@ -39,12 +39,6 @@ public:
insecure_rand = FastRandomContext(true);
}
int RandomInt(int nMax) override
{
state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash();
return (unsigned int)(state % nMax);
}
CAddrInfo* Find(const CService& addr, int* pnId = nullptr)
{
LOCK(cs);

View File

@ -22,40 +22,23 @@
* using BOOST_CHECK_CLOSE to fail.
*
*/
FastRandomContext local_rand_ctx(true);
BOOST_AUTO_TEST_SUITE(cuckoocache_tests);
/** insecure_GetRandHash fills in a uint256 from local_rand_ctx
*/
static void insecure_GetRandHash(uint256& t)
{
uint32_t* ptr = (uint32_t*)t.begin();
for (uint8_t j = 0; j < 8; ++j)
*(ptr++) = local_rand_ctx.rand32();
}
/* Test that no values not inserted into the cache are read out of it.
*
* There are no repeats in the first 200000 insecure_GetRandHash calls
*/
BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
{
local_rand_ctx = FastRandomContext(true);
SeedInsecureRand(true);
CuckooCache::cache<uint256, SignatureCacheHasher> cc{};
size_t megabytes = 4;
cc.setup_bytes(megabytes << 20);
uint256 v;
for (int x = 0; x < 100000; ++x) {
insecure_GetRandHash(v);
cc.insert(v);
cc.insert(InsecureRand256());
}
for (int x = 0; x < 100000; ++x) {
insecure_GetRandHash(v);
BOOST_CHECK(!cc.contains(v, false));
BOOST_CHECK(!cc.contains(InsecureRand256(), false));
}
};
@ -65,7 +48,7 @@ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
template <typename Cache>
static double test_cache(size_t megabytes, double load)
{
local_rand_ctx = FastRandomContext(true);
SeedInsecureRand(true);
std::vector<uint256> hashes;
Cache set{};
size_t bytes = megabytes * (1 << 20);
@ -75,7 +58,7 @@ static double test_cache(size_t megabytes, double load)
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j)
*(ptr++) = local_rand_ctx.rand32();
*(ptr++) = InsecureRand32();
}
/** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is
@ -136,7 +119,7 @@ template <typename Cache>
static void test_cache_erase(size_t megabytes)
{
double load = 1;
local_rand_ctx = FastRandomContext(true);
SeedInsecureRand(true);
std::vector<uint256> hashes;
Cache set{};
size_t bytes = megabytes * (1 << 20);
@ -146,7 +129,7 @@ static void test_cache_erase(size_t megabytes)
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j)
*(ptr++) = local_rand_ctx.rand32();
*(ptr++) = InsecureRand32();
}
/** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is
@ -199,7 +182,7 @@ template <typename Cache>
static void test_cache_erase_parallel(size_t megabytes)
{
double load = 1;
local_rand_ctx = FastRandomContext(true);
SeedInsecureRand(true);
std::vector<uint256> hashes;
Cache set{};
size_t bytes = megabytes * (1 << 20);
@ -209,7 +192,7 @@ static void test_cache_erase_parallel(size_t megabytes)
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j)
*(ptr++) = local_rand_ctx.rand32();
*(ptr++) = InsecureRand32();
}
/** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is
@ -301,7 +284,7 @@ static void test_cache_generations()
// iterations with non-deterministic values, so it isn't "overfit" to the
// specific entropy in FastRandomContext(true) and implementation of the
// cache.
local_rand_ctx = FastRandomContext(true);
SeedInsecureRand(true);
// block_activity models a chunk of network activity. n_insert elements are
// added to the cache. The first and last n/4 are stored for removal later
@ -318,7 +301,7 @@ static void test_cache_generations()
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)inserts[i].begin();
for (uint8_t j = 0; j < 8; ++j)
*(ptr++) = local_rand_ctx.rand32();
*(ptr++) = InsecureRand32();
}
for (uint32_t i = 0; i < n_insert / 4; ++i)
reads.push_back(inserts[i]);

View File

@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman)
{
CAddress addr(ip(GetRandInt(0xffffffff)), NODE_NONE);
CAddress addr(ip(insecure_rand_ctx.randbits(32)), NODE_NONE);
vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false));
CNode &node = *vNodes.back();
node.SetSendVersion(PROTOCOL_VERSION);

View File

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <netbase.h>
#include <net_permissions.h>
#include <protocol.h>
#include <serialize.h>
#include <streams.h>
@ -449,4 +450,82 @@ BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE);
}
BOOST_AUTO_TEST_CASE(netpermissions_test)
{
std::string error;
NetWhitebindPermissions whitebindPermissions;
NetWhitelistPermissions whitelistPermissions;
// Detect invalid white bind
BOOST_CHECK(!NetWhitebindPermissions::TryParse("", whitebindPermissions, error));
BOOST_CHECK(error.find("Cannot resolve -whitebind address") != std::string::npos);
BOOST_CHECK(!NetWhitebindPermissions::TryParse("127.0.0.1", whitebindPermissions, error));
BOOST_CHECK(error.find("Need to specify a port with -whitebind") != std::string::npos);
BOOST_CHECK(!NetWhitebindPermissions::TryParse("", whitebindPermissions, error));
// If no permission flags, assume backward compatibility
BOOST_CHECK(NetWhitebindPermissions::TryParse("1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK(error.empty());
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ISIMPLICIT);
BOOST_CHECK(NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
NetPermissions::ClearFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT);
BOOST_CHECK(!NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
NetPermissions::AddFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT);
BOOST_CHECK(NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
// Can set one permission
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER);
BOOST_CHECK(NetWhitebindPermissions::TryParse("@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
// Happy path, can parse flags
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,forcerelay@1.2.3.4:32", whitebindPermissions, error));
// forcerelay should also activate the relay permission
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY);
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,relay,noban@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,forcerelay,noban@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK(NetWhitebindPermissions::TryParse("all@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ALL);
// Allow dups
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,relay,noban,noban@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
// Allow empty
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,relay,,noban@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
BOOST_CHECK(NetWhitebindPermissions::TryParse(",@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
BOOST_CHECK(NetWhitebindPermissions::TryParse(",,@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
// Detect invalid flag
BOOST_CHECK(!NetWhitebindPermissions::TryParse("bloom,forcerelay,oopsie@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK(error.find("Invalid P2P permission") != std::string::npos);
// Check whitelist error
BOOST_CHECK(!NetWhitelistPermissions::TryParse("bloom,forcerelay,noban@1.2.3.4:32", whitelistPermissions, error));
BOOST_CHECK(error.find("Invalid netmask specified in -whitelist") != std::string::npos);
// Happy path for whitelist parsing
BOOST_CHECK(NetWhitelistPermissions::TryParse("noban@1.2.3.4", whitelistPermissions, error));
BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, PF_NOBAN);
BOOST_CHECK(NetWhitelistPermissions::TryParse("bloom,forcerelay,noban,relay@1.2.3.4/32", whitelistPermissions, error));
BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, PF_BLOOMFILTER | PF_FORCERELAY | PF_NOBAN | PF_RELAY);
BOOST_CHECK(error.empty());
BOOST_CHECK_EQUAL(whitelistPermissions.m_subnet.ToString(), "1.2.3.4/32");
BOOST_CHECK(NetWhitelistPermissions::TryParse("bloom,forcerelay,noban,relay,mempool@1.2.3.4/32", whitelistPermissions, error));
const auto strings = NetPermissions::ToStrings(PF_ALL);
BOOST_CHECK_EQUAL(strings.size(), 5);
BOOST_CHECK(std::find(strings.begin(), strings.end(), "bloomfilter") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "forcerelay") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "relay") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "noban") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "mempool") != strings.end());
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -209,8 +209,8 @@ public:
prevector_tester() {
SeedInsecureRand();
rand_seed = insecure_rand_seed;
rand_cache = insecure_rand_ctx;
rand_seed = InsecureRand256();
rand_cache = FastRandomContext(rand_seed);
}
};

View File

@ -48,11 +48,19 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U});
BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006});
}
FastRandomContext ctx3;
FastRandomContext ctx4;
BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
BOOST_CHECK(ctx3.rand256() != ctx4.rand256());
BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));
{
FastRandomContext ctx3, ctx4;
BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
}
{
FastRandomContext ctx3, ctx4;
BOOST_CHECK(ctx3.rand256() != ctx4.rand256());
}
{
FastRandomContext ctx3, ctx4;
BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));
}
}
BOOST_AUTO_TEST_CASE(fastrandom_randbits)

View File

@ -30,8 +30,7 @@
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
uint256 insecure_rand_seed = GetRandHash();
FastRandomContext insecure_rand_ctx(insecure_rand_seed);
FastRandomContext insecure_rand_ctx;
extern bool fPrintToConsole;
extern void noui_connect();

View File

@ -19,7 +19,6 @@
#include <boost/thread.hpp>
extern uint256 insecure_rand_seed;
extern FastRandomContext insecure_rand_ctx;
/**
@ -27,14 +26,9 @@ extern FastRandomContext insecure_rand_ctx;
*/
extern bool g_mock_deterministic_tests;
static inline void SeedInsecureRand(bool fDeterministic = false)
static inline void SeedInsecureRand(bool deterministic = false)
{
if (fDeterministic) {
insecure_rand_seed = uint256();
} else {
insecure_rand_seed = GetRandHash();
}
insecure_rand_ctx = FastRandomContext(insecure_rand_seed);
insecure_rand_ctx = FastRandomContext(deterministic);
}
static inline uint32_t InsecureRand32() { return insecure_rand_ctx.rand32(); }

View File

@ -100,8 +100,8 @@ void BuildChain(const uint256& root, int height, const unsigned int invalid_rate
{
if (height <= 0 || blocks.size() >= max_size) return;
bool gen_invalid = GetRand(100) < invalid_rate;
bool gen_fork = GetRand(100) < branch_rate;
bool gen_invalid = InsecureRandRange(100) < invalid_rate;
bool gen_fork = InsecureRandRange(100) < branch_rate;
const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root);
blocks.push_back(pblock);
@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
threads.create_thread([&blocks]() {
bool ignored;
for (int i = 0; i < 1000; i++) {
auto block = blocks[GetRand(blocks.size() - 1)];
auto block = blocks[InsecureRandRange(blocks.size() - 1)];
ProcessNewBlock(Params(), block, true, &ignored);
}

View File

@ -48,10 +48,6 @@ struct ChainTxData;
struct LockPoints;
/** Default for -whitelistrelay. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for -whitelistforcerelay. */
static const bool DEFAULT_WHITELISTFORCERELAY = true;
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
//! -maxtxfee default
@ -135,8 +131,6 @@ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
/** Maximum number of unconnecting headers announcements before DoS score */
static const int MAX_UNCONNECTING_HEADERS = 10;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;

View File

@ -0,0 +1,103 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test p2p permission message.
Test that permissions are correctly calculated and applied
"""
from test_framework.test_node import ErrorMatch
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes,
p2p_port,
)
class P2PPermissionsTests(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [[],[]]
def run_test(self):
self.checkpermission(
# default permissions (no specific permissions)
["-whitelist=127.0.0.1"],
["relay", "noban", "mempool"],
True)
self.checkpermission(
# relay permission removed (no specific permissions)
["-whitelist=127.0.0.1", "-whitelistrelay=0"],
["noban", "mempool"],
True)
self.checkpermission(
# forcerelay and relay permission added
# Legacy parameter interaction which set whitelistrelay to true
# if whitelistforcerelay is true
["-whitelist=127.0.0.1", "-whitelistforcerelay"],
["forcerelay", "relay", "noban", "mempool"],
True)
# Let's make sure permissions are merged correctly
# For this, we need to use whitebind instead of bind
# by modifying the configuration file.
ip_port = "127.0.0.1:{}".format(p2p_port(1))
self.replaceinconfig(1, "bind=127.0.0.1", "whitebind=bloomfilter,forcerelay@" + ip_port)
self.checkpermission(
["-whitelist=noban@127.0.0.1" ],
# Check parameter interaction forcerelay should activate relay
["noban", "bloomfilter", "forcerelay", "relay" ],
False)
self.replaceinconfig(1, "whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1")
self.checkpermission(
# legacy whitelistrelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"],
["noban", "mempool"],
False)
self.checkpermission(
# legacy whitelistforcerelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"],
["noban", "mempool"],
False)
self.checkpermission(
# missing mempool permission to be considered legacy whitelisted
["-whitelist=noban@127.0.0.1"],
["noban"],
False)
self.checkpermission(
# all permission added
["-whitelist=all@127.0.0.1"],
["forcerelay", "noban", "mempool", "bloomfilter", "relay"],
False)
self.stop_node(1)
self.nodes[1].assert_start_raises_init_error(["-whitelist=oopsie@127.0.0.1"], "Invalid P2P permission", match=ErrorMatch.PARTIAL_REGEX)
self.nodes[1].assert_start_raises_init_error(["-whitelist=noban@127.0.0.1:230"], "Invalid netmask specified in", match=ErrorMatch.PARTIAL_REGEX)
self.nodes[1].assert_start_raises_init_error(["-whitebind=noban@127.0.0.1/10"], "Cannot resolve -whitebind address", match=ErrorMatch.PARTIAL_REGEX)
def checkpermission(self, args, expectedPermissions, whitelisted):
self.restart_node(1, args)
connect_nodes(self.nodes[0], 1)
peerinfo = self.nodes[1].getpeerinfo()[0]
assert_equal(peerinfo['whitelisted'], whitelisted)
assert_equal(len(expectedPermissions), len(peerinfo['permissions']))
for p in expectedPermissions:
if not p in peerinfo['permissions']:
raise AssertionError("Expected permissions %r is not granted." % p)
def replaceinconfig(self, nodeid, old, new):
with open(self.nodes[nodeid].bitcoinconf, encoding="utf8") as f:
newText=f.read().replace(old, new)
with open(self.nodes[nodeid].bitcoinconf, 'w', encoding="utf8") as f:
f.write(newText)
if __name__ == '__main__':
P2PPermissionsTests().main()

47
test/functional/rpc_setban.py Executable file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the setban rpc call."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
connect_nodes,
p2p_port
)
class SetBanTests(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [[],[]]
def run_test(self):
# Node 0 connects to Node 1, check that the noban permission is not granted
connect_nodes(self.nodes[0], 1)
peerinfo = self.nodes[1].getpeerinfo()[0]
assert(not 'noban' in peerinfo['permissions'])
# Node 0 get banned by Node 1
self.nodes[1].setban("127.0.0.1", "add")
# Node 0 should not be able to reconnect
with self.nodes[1].assert_debug_log(expected_msgs=['dropped (banned)\n']):
self.restart_node(1, [])
self.nodes[0].addnode("127.0.0.1:" + str(p2p_port(1)), "onetry")
# However, node 0 should be able to reconnect if it has noban permission
self.restart_node(1, ['-whitelist=127.0.0.1'])
connect_nodes(self.nodes[0], 1)
peerinfo = self.nodes[1].getpeerinfo()[0]
assert('noban' in peerinfo['permissions'])
# If we remove the ban, Node 0 should be able to reconnect even without noban permission
self.nodes[1].setban("127.0.0.1", "remove")
self.restart_node(1, [])
connect_nodes(self.nodes[0], 1)
peerinfo = self.nodes[1].getpeerinfo()[0]
assert(not 'noban' in peerinfo['permissions'])
if __name__ == '__main__':
SetBanTests().main()

View File

@ -64,6 +64,7 @@ class TestNode():
self.index = i
self.datadir = datadir
self.chain = chain
self.bitcoinconf = os.path.join(self.datadir, "dash.conf")
self.stdout_dir = os.path.join(self.datadir, "stdout")
self.stderr_dir = os.path.join(self.datadir, "stderr")
self.rpchost = rpchost

View File

@ -137,6 +137,7 @@ BASE_SCRIPTS = [
'wallet_keypool.py',
'wallet_keypool_hd.py',
'p2p_mempool.py',
'rpc_setban.py',
'mining_prioritisetransaction.py',
'p2p_invalid_locator.py',
'p2p_invalid_block.py',
@ -194,6 +195,7 @@ BASE_SCRIPTS = [
'feature_includeconf.py',
'feature_logging.py',
'p2p_node_network_limited.py',
'p2p_permissions.py',
'feature_blocksdir.py',
'feature_config_args.py',
'rpc_help.py',

View File

@ -6,3 +6,4 @@ objext
unparseable
unselect
useable
setban