aboutsummaryrefslogtreecommitdiff
path: root/src/net.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.h')
-rw-r--r--src/net.h184
1 files changed, 128 insertions, 56 deletions
diff --git a/src/net.h b/src/net.h
index 37aaf1a63b..f33147155a 100644
--- a/src/net.h
+++ b/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>
@@ -39,6 +40,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). */
@@ -55,10 +61,12 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
/** Maximum length of the user agent string in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
-/** Maximum number of automatic outgoing nodes */
-static const int MAX_OUTBOUND_CONNECTIONS = 8;
+/** Maximum number of automatic outgoing nodes over which we'll relay everything (blocks, tx, addrs, etc) */
+static const int MAX_OUTBOUND_FULL_RELAY_CONNECTIONS = 8;
/** Maximum number of addnode outgoing nodes */
static const int MAX_ADDNODE_CONNECTIONS = 8;
+/** Maximum number of block-relay-only outgoing connections */
+static const int MAX_BLOCKS_ONLY_CONNECTIONS = 2;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@@ -125,7 +133,8 @@ public:
{
ServiceFlags nLocalServices = NODE_NONE;
int nMaxConnections = 0;
- int nMaxOutbound = 0;
+ int m_max_outbound_full_relay = 0;
+ int m_max_outbound_block_relay = 0;
int nMaxAddnode = 0;
int nMaxFeeler = 0;
int nBestHeight = 0;
@@ -138,8 +147,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;
@@ -148,10 +158,12 @@ public:
void Init(const Options& connOptions) {
nLocalServices = connOptions.nLocalServices;
nMaxConnections = connOptions.nMaxConnections;
- nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections);
+ m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
+ m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay;
m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing;
nMaxAddnode = connOptions.nMaxAddnode;
nMaxFeeler = connOptions.nMaxFeeler;
+ m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler;
nBestHeight = connOptions.nBestHeight;
clientInterface = connOptions.uiInterface;
m_banman = connOptions.m_banman;
@@ -190,7 +202,7 @@ public:
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
void SetNetworkActive(bool active);
- void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false);
+ void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false, bool block_relay_only = false);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -246,7 +258,7 @@ public:
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses();
- // This allows temporarily exceeding nMaxOutbound, with the goal of finding
+ // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
// a peer that is better than all our current peers.
void SetTryNewOutboundPeer(bool flag);
bool GetTryNewOutboundPeer();
@@ -270,6 +282,12 @@ public:
bool DisconnectNode(const CNetAddr& addr);
bool DisconnectNode(NodeId id);
+ //! Used to convey which local services we are offering peers during node
+ //! connection.
+ //!
+ //! The data returned by this is used in CNode construction,
+ //! which is used to advertise which services we are offering
+ //! that peer during `net_processing.cpp:PushNodeVersion()`.
ServiceFlags GetLocalServices() const;
//!set the max outbound target in bytes
@@ -314,15 +332,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();
@@ -346,8 +366,8 @@ private:
CNode* FindNode(const CService& addr);
bool AttemptToEvictConnection();
- CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection);
- bool IsWhitelistedRange(const CNetAddr &addr);
+ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection, bool block_relay_only);
+ void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
void DeleteNode(CNode* pnode);
@@ -380,7 +400,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{0};
unsigned int nReceiveFloodSize{0};
@@ -399,15 +419,34 @@ private:
std::atomic<NodeId> nLastNodeId{0};
unsigned int nPrevNodeCount{0};
- /** Services this instance offers */
+ /**
+ * Services this instance offers.
+ *
+ * This data is replicated in each CNode instance we create during peer
+ * connection (in ConnectNode()) under a member also called
+ * nLocalServices.
+ *
+ * This data is not marked const, but after being set it should not
+ * change. See the note in CNode::nLocalServices documentation.
+ *
+ * \sa CNode::nLocalServices
+ */
ServiceFlags nLocalServices;
std::unique_ptr<CSemaphore> semOutbound;
std::unique_ptr<CSemaphore> semAddnode;
int nMaxConnections;
- int nMaxOutbound;
+
+ // How many full-relay (tx, block, addr) outbound peers we want
+ int m_max_outbound_full_relay;
+
+ // How many block-relay only outbound peers we want
+ // We do not relay tx or addr messages with these peers
+ int m_max_outbound_block_relay;
+
int nMaxAddnode;
int nMaxFeeler;
+ int m_max_outbound;
bool m_use_addrman_outgoing;
std::atomic<int> nBestHeight;
CClientUIInterface* clientInterface;
@@ -433,7 +472,7 @@ private:
std::thread threadMessageHandler;
/** flag for deciding to connect to an extra outbound peer,
- * in excess of nMaxOutbound
+ * in excess of m_max_outbound_full_relay
* This takes the place of a feeler connection */
std::atomic_bool m_try_another_outbound_peer;
@@ -448,7 +487,6 @@ void StartMapPort();
void InterruptMapPort();
void StopMapPort();
unsigned short GetListenPort();
-bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
struct CombinerAll
{
@@ -555,7 +593,8 @@ public:
mapMsgCmdSize mapSendBytesPerMsgCmd;
uint64_t nRecvBytes;
mapMsgCmdSize mapRecvBytesPerMsgCmd;
- bool fWhitelisted;
+ NetPermissionFlags m_permissionFlags;
+ bool m_legacyWhitelisted;
double dPingTime;
double dPingWait;
double dMinPing;
@@ -657,7 +696,11 @@ public:
*/
std::string cleanSubVer GUARDED_BY(cs_SubVer){};
bool m_prefer_evict{false}; // This peer is preferred for eviction.
- bool fWhitelisted{false}; // This peer can bypass DoS banning.
+ 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{false}; // If true this node is being used as a short lived feeler.
bool fOneShot{false};
bool m_manual_connection{false};
@@ -668,15 +711,8 @@ public:
// Setting fDisconnect to true will cause the node to be disconnected the
// next time DisconnectNodes() runs
std::atomic_bool fDisconnect{false};
- // We use fRelayTxes for two purposes -
- // a) it allows us to not relay tx invs before receiving the peer's version message
- // b) the peer may tell us in its version message that we should not relay tx invs
- // unless it loads a bloom filter.
- bool fRelayTxes GUARDED_BY(cs_filter){false};
bool fSentAddr{false};
CSemaphoreGrant grantOutbound;
- mutable CCriticalSection cs_filter;
- std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter);
std::atomic<int> nRefCount{0};
const uint64_t nKeyedNetGroup;
@@ -695,28 +731,51 @@ public:
std::vector<CAddress> vAddrToSend;
CRollingBloomFilter addrKnown;
bool fGetAddr{false};
- std::set<uint256> setKnown;
int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing){0};
int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing){0};
- // inventory based relay
- CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_inventory);
- // Set of transaction ids we still have to announce.
- // They are sorted by the mempool before relay, so the order is not important.
- std::set<uint256> setInventoryTxToSend;
+ const bool m_addr_relay_peer;
+ bool IsAddrRelayPeer() const { return m_addr_relay_peer; }
+
// List of block ids we still have announce.
// There is no final sorting before sending, as they are always sent immediately
// and in the order requested.
std::vector<uint256> vInventoryBlockToSend GUARDED_BY(cs_inventory);
CCriticalSection cs_inventory;
- int64_t nNextInvSend{0};
+
+ struct TxRelay {
+ TxRelay() { pfilter = MakeUnique<CBloomFilter>(); }
+ mutable CCriticalSection cs_filter;
+ // We use fRelayTxes for two purposes -
+ // a) it allows us to not relay tx invs before receiving the peer's version message
+ // b) the peer may tell us in its version message that we should not relay tx invs
+ // unless it loads a bloom filter.
+ bool fRelayTxes GUARDED_BY(cs_filter){false};
+ std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter) GUARDED_BY(cs_filter);
+
+ mutable CCriticalSection cs_tx_inventory;
+ CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_tx_inventory){50000, 0.000001};
+ // Set of transaction ids we still have to announce.
+ // They are sorted by the mempool before relay, so the order is not important.
+ std::set<uint256> setInventoryTxToSend;
+ // Used for BIP35 mempool sending
+ bool fSendMempool GUARDED_BY(cs_tx_inventory){false};
+ // Last time a "MEMPOOL" request was serviced.
+ std::atomic<int64_t> timeLastMempoolReq{0};
+ int64_t nNextInvSend{0};
+
+ CCriticalSection cs_feeFilter;
+ // Minimum fee rate with which to filter inv's to this node
+ CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0};
+ CAmount lastSentFeeFilter{0};
+ int64_t nextSendTimeFeeFilter{0};
+ };
+
+ // m_tx_relay == nullptr if we're not relaying transactions with this peer
+ std::unique_ptr<TxRelay> m_tx_relay;
+
// Used for headers announcements - unfiltered blocks to relay
std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory);
- // Used for BIP35 mempool sending
- bool fSendMempool GUARDED_BY(cs_inventory){false};
-
- // Last time a "MEMPOOL" request was serviced.
- std::atomic<int64_t> timeLastMempoolReq{0};
// Block and TXN accept times
std::atomic<int64_t> nLastBlockTime{0};
@@ -733,15 +792,10 @@ public:
std::atomic<int64_t> nMinPingUsecTime{std::numeric_limits<int64_t>::max()};
// Whether a ping is requested.
std::atomic<bool> fPingQueued{false};
- // Minimum fee rate with which to filter inv's to this node
- CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0};
- CCriticalSection cs_feeFilter;
- CAmount lastSentFeeFilter{0};
- int64_t nextSendTimeFeeFilter{0};
std::set<uint256> orphan_work_set;
- CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false);
+ CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false, bool block_relay_only = false);
~CNode();
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
@@ -749,10 +803,27 @@ public:
private:
const NodeId id;
const uint64_t nLocalHostNonce;
- // Services offered to this peer
+
+ //! Services offered to this peer.
+ //!
+ //! This is supplied by the parent CConnman during peer connection
+ //! (CConnman::ConnectNode()) from its attribute of the same name.
+ //!
+ //! This is const because there is no protocol defined for renegotiating
+ //! services initially offered to a peer. The set of local services we
+ //! offer should not change after initialization.
+ //!
+ //! An interesting example of this is NODE_NETWORK and initial block
+ //! download: a node which starts up from scratch doesn't have any blocks
+ //! to serve, but still advertises NODE_NETWORK because it will eventually
+ //! fulfill this role after IBD completes. P2P code is written in such a
+ //! way that it can gracefully handle peers who don't make good on their
+ //! service advertisements.
const ServiceFlags nLocalServices;
+
const int nMyStartingHeight;
int nSendVersion{0};
+ NetPermissionFlags m_permissionFlags{ PF_NONE };
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
mutable CCriticalSection cs_addrName;
@@ -833,20 +904,21 @@ public:
void AddInventoryKnown(const CInv& inv)
{
- {
- LOCK(cs_inventory);
- filterInventoryKnown.insert(inv.hash);
+ if (m_tx_relay != nullptr) {
+ LOCK(m_tx_relay->cs_tx_inventory);
+ m_tx_relay->filterInventoryKnown.insert(inv.hash);
}
}
void PushInventory(const CInv& inv)
{
- LOCK(cs_inventory);
- if (inv.type == MSG_TX) {
- if (!filterInventoryKnown.contains(inv.hash)) {
- setInventoryTxToSend.insert(inv.hash);
+ if (inv.type == MSG_TX && m_tx_relay != nullptr) {
+ LOCK(m_tx_relay->cs_tx_inventory);
+ if (!m_tx_relay->filterInventoryKnown.contains(inv.hash)) {
+ m_tx_relay->setInventoryTxToSend.insert(inv.hash);
}
} else if (inv.type == MSG_BLOCK) {
+ LOCK(cs_inventory);
vInventoryBlockToSend.push_back(inv.hash);
}
}