The PR branch HEAD was f8ff628 at the time of this review club meeting.
Notes
Compact blocks are a way to relay blocks across the Bitcoin P2P network with
reduced bandwidth usage. They can also reduce block propagation latency when
used in BIP152 high-bandwidth mode.
BIP152 is the
specification for compact blocks.
BIP152 was originally developed and deployed before segwit was activated;
Bitcoin Core’s implementation was merged in PR
8068 and included in the v0.13.0
release. The specification was made extensible so that compact blocks could be
used for non-witness serialized blocks (version 1) and witness serialized
blocks (version 2).
Segwit (BIP141) was
activated in August 2017. Every version of Bitcoin Core since v0.13.1 supports
segwit and will fully validate blocks according to the BIP141 consensus
rules. To fully validate a block with segwit transactions, it must be
serialized with witnesses.
Version 1 (non-witness) compact blocks are therefore no longer useful to peers on the
network. This PR removes support for serving version 1 compact blocks.
Questions
How does using compact blocks save bandwidth? What data is not downloaded
when relaying blocks using compact blocks?
What is BIP152 high-bandwidth mode? How many of our peers can we choose to be
high-bandwidth peers?
How do we choose which peers should be high-bandwidth peers? In which
function does that logic exist?
If a peer chooses us to be its high-bandwidth peer, how does it signal
that to us?
BIP152 states: “high-bandwidth mode permits relaying of CMPCTBLOCK messages
prior to full validation (requiring only that the block header is valid
before relay).” In which PeerManager function do we relay compact blocks
to peers that have chosen us to be a high-bandwidth peer?
How is that PeerManager function invoked? In which thread is it called?
<jnewbery> A couple of reminders on the format: i have some prepared questions to guide the conversation, but feel free to jump in at any time. Don't worry if you have a question about something that we covered earlier or whatever.
<jarolrod> Compact Blocks only includes a short transaction id for each transaction contained within it. The node on the receiving end of a compact block must match a transaction id with a transaction in its mempool and reconstruct the full block. Since we are not sending all of the transaction data, we can reduce block relay bandwidth around ~90%
<emzy> We only send the block header and short IDs of the transactions. If the peer has all the transactions in the mempool it can reconstruct the block without additional data.
<pinheadmz> michaelfolkson i think an important point is that no one will ever need version 1 compact blocks because the last non witness block was so long ago, and compacts only work for recent blocks
<jnewbery> Lots of great answers there. Yes, when the node sends a CMPCTBLOCK it'll include shortids for the transactions, and some prefilled transactions, including the coinbase
<sdaftuar> pinheadmz: but you are right that reconstruction would always require a roundtrip because those witness transactions would be nonstadnard to an 0.13.0 node
<norisg> did the block structure also change with segwit, you are talking about "non witness blocks", non witness blocks have no segwit transactions in it?
<anir> peers send new block announcements with the short transaction IDs already via a cmpctblock message, and it’s enabled by setting the first boolean to 1 in a sendcmpct message
<AnthonyRonning> High bandwidth mode is available so that peers can receive blocks automatically and asap (`1.5 * RTT`), even before full block validation takes place.
<jnewbery> olympics: tx relay (for unconfirmed transactions) is unaffected by this. compact blocks makes block propogation faster based on the observation that the receiver probably has most of the transactions in their mempool already
<jarolrod> high bandwidth mode is when you send cmpct blocks without asking for permission, can lead to higher bandwidth because you can receive the same block more than once, but reduced latency because potentially less round trips
<lightlike> when it was introduced, why wasn't it decided to schedule compact blocks after segwit? Seems like a lot of effort for just one version 0.13.0
<AnthonyRonning> one thing I was unsure of, bip152 says "Nodes MUST NOT send such sendcmpct messages to more than three peers" but sendcmpct can be for low bandwitdth too, so is the three limit total or high bandwidth?
<theStack> it should not only affect 0.13.0 but also other higher versions that don't have activated segwit yet, right? (afair segwit came with v0.17, so there must be some versions v0.14.x and v0.15.x etc. with non-latest minor number that are affected)
<sipa> lightlike: so at the time it was included, it worked immediately on the network, and would keep doing so regardless of whether segwit activated or not (which turned out to be... uncertain for a while)
<jnewbery> ... or indeed if it would ever be activated. Segwit and compact blocks are indepedently good things, so it doesn't make sense to gate one on the other
<jnewbery> theStack: the code for segwit was merged in bitcoin 0.13.1. Activation was later, but any node on 0.13.1 or higher can understand/validate/relay segwit blocks/txs
<willcl_ark> ccdle12: as per BIP152: "Nodes MUST NOT send such sendcmpct messages to more than three peers, as it encourages wasting outbound bandwidth across the network."
<sipa> AnthonyRonning: the hb peers will just send the compact block without being asked for it; the lb peers will announce "hey i have a compact block for you, want it?" - and then the receiver gets to pick which of the lb peers to ask it from
<jnewbery> Next question (should be easy given the link above): How do we choose which peers should be high-bandwidth peers? In which function does that logic exist?
<AnthonyRonning> High bandwidth mode is for peers that have a past performance in providing blocks quickly. I believe it exists in `MaybeSetPeerAsAnnouncingHeaderAndIDs`
<norisg> sipa: what was the reason why we had to implement it in the first place, but did't remove it immediatly when introducing "segwit-supporting compact block version"
<pinheadmz> jnewbery in the updated code, if i send you SENDCMPCT with version 1, the function just returns. So you will not send me compact blocks - is my node "ok with this"? Or do we disconnect from peers that dont send compact blocks after we ask them to ?
<jnewbery> pinheadmz: Very good question. I think Bitcoin Core would be "ok with this", but it's maybe worth a quick check in the Bitcoin Core 0.13.0 code. If it's not ok with it, then maybe a polite disconnect would be better.
<AnthonyRonning> if I forked core to connect to all my peers with high bandwith mode, is that allowed? can the network see I have connected to more than 3?
<jnewbery> AnthonyRonning: no-one can stop you, but the BIP says you shouldn't: Nodes MUST NOT send such sendcmpct messages to more than three peers, as it encourages wasting outbound bandwidth across the network.
<norisg> does the network equally distribute the high bath width connection, lets say we have 5 nodes on the network and each one of them is connected to the same other 3 in high band with, how do we get the other one in
<jnewbery> it can also be called from ConnectTip, if we tried to connect the block, but it failed at that point (e.g. if it spent coins that didn't exist)
<jnewbery> the interesting thing to note here is that CheckBlock is one of the two validation interface callbacks that are called synchronously. Does anyone know the other one?
<pinheadmz> jnewbery tracing through net_processing I think the requesting node doesnt care if it gets a block instead of a compact block. Even if the inv has type MSG_CMPCT_BLOCK, the remote node just tests for IsGenBlkMsg which includes all block tpe messages, and then decides later to send compact or not
<jnewbery> ok, we can come back to the validation interface in a bit. Let's move on to the next question. If a peer chooses us to be its high-bandwidth peer, how does it signal that to us?
<jnewbery> Next question. BIP152 states: “high-bandwidth mode permits relaying of CMPCTBLOCK messages prior to full validation (requiring only that the block header is valid before relay).” In which PeerManager function do we relay compact blocks to peers that have chosen us to be a high-bandwidth peer?
<jnewbery> AnthonyRonning jarolrod: exactly right. It's in NewPOWValidBlock(). Can anyone tell me more about NewPOWValidBlock? Where is it called from?
<sipa> norisg: it's not; but verification takes time, and latency on the network is important, so we want blocks to be able to propagate without suffering a delay from validation at every hop
<jnewbery> many of those notifications are asynchronous (i.e. validation sends them, and then the subscibers get notified by a background thread), but there are a couple that are synchronous (i.e. the subscribers are called directly by the thread in validation)
<jnewbery> so we immediately (synchronously) call the NewPoWValidBlock() callback in net_processing, which sends the cmpctblock message out immediately
<jnewbery> larryruane_: validation doesn't hold a reference/pointer to peermanager. Everything that peermanager gets from validation is through the validation interface
<nehan> jnewbery: so the documentation that NewPoWValidBlock is synchronous vs asynchronous is the fact that it does *not* have "Called in a background thread" in its defn comments in validationinterface.h?
<jnewbery> nehan: that's the documentation, yes! You could look in validationinterface.cpp to see how those notifications are invoked, or you could run a node with thread debug logs enabled and validation category debug logs enabled and see which threads are servicing the validation interface callbacks