mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge pull request #4277 from PastaPastaPasta/backport-more-p2p
Backport more p2p
This commit is contained in:
commit
a4f06c90ed
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
20
src/init.cpp
20
src/init.cpp
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
89
src/net.cpp
89
src/net.cpp
@ -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
|
||||
|
56
src/net.h
56
src/net.h
@ -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
105
src/net_permissions.cpp
Normal 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
62
src/net_permissions.h
Normal 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
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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"));
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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(); }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
103
test/functional/p2p_permissions.py
Executable file
103
test/functional/p2p_permissions.py
Executable 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
47
test/functional/rpc_setban.py
Executable 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()
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -6,3 +6,4 @@ objext
|
||||
unparseable
|
||||
unselect
|
||||
useable
|
||||
setban
|
||||
|
Loading…
Reference in New Issue
Block a user