net processing: Reduce resource usage for inbound block-relay-only connections #22778 #8
Replies: 2 comments
-
Extra Reading
|
Beta Was this translation helpful? Give feedback.
-
SummaryPR #22778 conditionally initializes This reduces resource usage ~5MB for ten such peers.
// We only initialize the m_tx_relay data structure if:
// - this isn't an outbound block-relay-only connection; and
// - fRelay=true or we're offering NODE_BLOOM to this peer
// (NODE_BLOOM means that the peer may turn on tx relay later)
if (!pfrom.IsBlockOnlyConn() &&
(fRelay || (pfrom.GetLocalServices() & NODE_BLOOM))) {
auto* const tx_relay = peer->SetTxRelay();
{
LOCK(tx_relay->m_bloom_filter_mutex);
tx_relay->m_relay_txs = fRelay; // set to true after we get the first filter* message
}
if (fRelay) pfrom.m_relays_txs = true;
} What’s a bloom filter?Bloom filter is probabilistic filter used to filter transaction, addresses etc to a Peer. /**
* BloomFilter is a probabilistic filter which SPV clients provide
* so that we can filter the transactions we send them.
*
* This allows for significantly more efficient transaction and block downloads.
*
* Because bloom filters are probabilistic, a SPV node can increase the false-
* positive rate, making us send it transactions which aren't actually its,
* allowing clients to trade more bandwidth for more privacy by obfuscating which
* keys are controlled by them.
*/
class CBloomFilter
{
private:
std::vector<unsigned char> vData;
unsigned int nHashFuncs;
unsigned int nTweak;
unsigned char nFlags;
... If a node advertises Bloom-Filter related NetMessages: /**
* The filterload message tells the receiving peer to filter all relayed
* transactions and requested merkle blocks through the provided filter.
* @since protocol version 70001 as described by BIP37.
* Only available with service bit NODE_BLOOM since protocol version
* 70011 as described by BIP111.
*/
extern const char* FILTERLOAD;
/**
* The filteradd message tells the receiving peer to add a single element to a
* previously-set bloom filter, such as a new public key.
* @since protocol version 70001 as described by BIP37.
* Only available with service bit NODE_BLOOM since protocol version
* 70011 as described by BIP111.
*/
extern const char* FILTERADD;
/**
* The filterclear message tells the receiving peer to remove a previously-set
* bloom filter.
* @since protocol version 70001 as described by BIP37.
* Only available with service bit NODE_BLOOM since protocol version
* 70011 as described by BIP111.
*/
extern const char* FILTERCLEAR;
/**
* Indicates that a node prefers to receive new block announcements via a
* "headers" message rather than an "inv".
* @since protocol version 70012 as described by BIP130.
*/ A Hands on tutorial to understand bloom filters: https://llimllib.github.io/bloomfilter-tutorial/ Why are some peers block-relay-only? Briefly, what’s the purpose of having some peers being block-relay-only?
This PR reduces resource usage. Which resource is reduced and by how much?By skipping the initialization of This review comment includes a rough estimate on resource-saving, which is about 5MB for 10 Peers. Why is the TxRelay object separate from the Peer object?
Keeping the Why is NODE_BLOOM not the default behavior (why does a node choose to advertise it, or not, using a service bit)? Why do most nodes apparently not enable this service?There are well-known privacy and DOS vectors over BIP37, and SPV mechanism has been upgraded to use BIP157 instead.
More limitations on Bloom Filter based SPVs can be found in this lopp.net blog post
There are two kinds of bloom filters used across the code.
Different filters are used for different types of relaying situations. Why would a peer send us fRelay = false in the version message? Why might a peer send us fRelay = false if it wasn’t planning to send us a filterload?
This behaviour is reflected in the implementation of if (msg_type == NetMsgType::FILTERLOAD) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
LogPrint(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
CBloomFilter filter;
vRecv >> filter;
if (!filter.IsWithinSizeConstraints())
{
// There is no excuse for sending a too-large filter
Misbehaving(pfrom.GetId(), 100, "too-large bloom filter");
} else if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) {
{
LOCK(tx_relay->m_bloom_filter_mutex);
tx_relay->m_bloom_filter.reset(new CBloomFilter(filter));
tx_relay->m_relay_txs = true;
}
pfrom.m_bloom_filter_loaded = true;
}
return;
} Notice how it's setting the This PR is divided into four commits. What are some principles we should follow when deciding on how to distribute the changes among the commits?This PR is an excellent education candidate on "how to create good commits". Looking at the structure, some important patterns can be identified.
#Bonus Questions This PR adds GetTxRelay() to safely (using a mutex) return a pointer to a peer’s TxRelay structure. If the a call to GetTxRelay() (for example, this one) returns a non-null pointer, then the pointer is used without holding the mutex. What prevents the TxRelay structure from being deallocated just after the pointer to it is returned by GetTxRelay(), making the pointer invalid?Answers welcome!! Some class variables are annotated mutable. What does this mean? Hint: This is fairly common with mutex variables.We mark variables as The pointer variable tx_relay is initialized as const, but it’s used to mutate the TxRelay structure it’s pointing to. How is that possible?The pointer in question is a |
Beta Was this translation helpful? Give feedback.
-
Session Details
Summary
Inferring
block-relay-only
connections from version messages and skipping the initialization of specific structures can reduce resource usage.Learning
net_processing.cpp
.Beta Was this translation helpful? Give feedback.
All reactions