After a block is mined it is broadcast to the p2p network where it will eventually
be relayed to all nodes on the network. There are two methods available
for relaying blocks: legacy relay and compact block relay.
Legacy Relay: A node participating in legacy relaying will always send or
request entire blocks. For nodes that maintain a mempool this is quite
bandwidth inefficient, since they probably already have most of the
transactions from a new block in their mempool.
Compact Block Relay: Compact block relay is specified in BIP 152.
The goal is to address the bandwidth inefficiencies of legacy relaying by
only relaying the transactions of a new block that the requesting peer has not
yet seen. Check out this Compact Blocks FAQ
for bechmarks and more info.
Bitcoin Core 0.12 introduced a -blocksonly setting that can reduce a node’s
bandwidth usage by 88%. The reduction is achieved by not participating in
transaction relay. For more info check out this post
on blocksonly mode by Gregory Maxwell. Blocksonly nodes currently use
compact block relaying to download blocks even though they don’t maintain
a full mempool.
This PR makes blocksonly nodes use legacy relaying to download new blocks.
What do you think of Gleb’s comments
on the usage of sendrawtransaction? Can you think of other exceptions in
which a blocksonly node would still want to download compact blocks?
<amiti> I started tinkering with the functional test, but I'm getting surprising results. I thought one difference would be a blocksonly node sending sendcmpct with 0 vs 1, but that's not what I'm getting in the tests 🤔
<larryruane> i did have a question about case C, low bandwidth relaying ... since node B is sending a getdata(CMPCT) message, why is it necessary for that node to announce ahead of time that it wants to use this mode (the sendcmpct(0) message?
<larryruane> so for example, let's say node B doesn't send the sendcmpct(0) message ... then later sends a getdata(CMPCT)? is that just a protocol error?
<theStack> ad legacy relaying diagram: what does it depend on whether a peer is notified via headers or via inv? (according to the protocol documentation, headers is only sent in response to getheaders: https://en.bitcoin.it/wiki/Protocol_documentation#headers)
<lightlike> we can also revert to inv-mode - at least, this seems to happen sometimes in the functional tests intermittently, when the CI has strange delays for some reason
<jnewbery> larryruane: I think you can think of a sendcmpct(0, version) to mean "I can provide compact blocks" and a sendcmpct(1, version) to mean "I want you to use HB compact blocks to announce new blocks"
<lightlike> dergoegge: Are you sure? I thought they do have a mempool as well, it is just not updated via p2p? for example, if I restart a normal node with a full mempool into blocks-only mode, the mempool will still be full?!
<jnewbery> I don't think there's currently a config option to switch the mempool off entirely, although it shouldn't be too much work to implement that now that so much work has been done to separate out the components
<dergoegge> amiti theStack: yes so blocksonly nodes can and should still serve compact blocks since they really only the entire block to be able to do that
<larryruane> hey in case this may be useful to anyone else, to measure the bandwidth of your local bitcoind, run `sudo iftop -f 'port 8333' in another window (on linux, you may have to apt install it)
<lightlike> I think the naming of the variable m_ignore_incoming_txs is a bit misleading. we don't just ignore them, we'll disconnect the peer if they send us txes.
<jnewbery> (the reason we disconnect is that it's a violation of the protocol. We've sent them fRelay=false in our version message to them, requesting that they don't relay txs to us)
<willcl_ark> Agree the name could be changed, but I quite like the behaviour, it's better for low-bandwidth nodes to disconnect if people start sending you unsolicited messages, wasting your bandwidth
<larryruane> notice too that at least by default, we set up a block-relay-only connection to some of our peers, even without the local `-blocksonly` flag ... does that cause `ignores_incoming_txs` to be set to true?
<dergoegge> JanB: almost correct, there is a second step to defaulting to legacy relay. by not sending sendcmpct(1) we don't request high bandwidth mode, so our peer won't send us cmcptblock messages to announce blocks.
<amiti> larryruane: I don't think so. I could be running a node with a full mempool and have a block-relay-only connection to you. Just because you don't send me txns doesn't mean I necessarily don't already have them to reconstruct the block from short ids.
<amiti> with -blocksonly mode, although its possible I have mempool txns based on edge cases, most likely I don't have mempool txns, so will need to get all the transactions
<dergoegge> raj: we actually need to still send sendcmpct(0) otherwise a peer won't request compact blocks and a blocksonly node still wants to serve those
<jnewbery> lightlike: amiti: (I know you know this alredy, but for everyone else) block-relay-only connections also don't gossip addrs, so even in blocksonly mode their behaviour is slightly different from the other connections
<theStack> so if i see that correctly, at the point of the diff where the second change occurs, the GETDATA message is already prepared to request the full block, and we add an additional condition (!m_ignore_incoming_txs) to when to modify the message to request compact blocks
<amiti> dergoegge: even with the guard to MaybeSetPeersAsAnnouncing... commented out, the sendcmpct announce bool was set to False for a blocksonly node. I thought this is what that clause would change (so, true on master, false on PR). but I might be missing something in my test setup or my understanding =P
<larryruane> theStack: looks like to me too, and also I found it interesting (not changed by this PR) that only the first entry in the CInv vector needs to say MSG_CMPCT_BLOCK ... all the others can still say MSG_BLOCK
<lightlike> larryruane: One more thought about your earlier question: I think the main reason for having block-relay-only connections is to not be subjected to privacy issues with tx and addr relay. By allowing compactblock downloading, you do reveal something about your mempool to them which you otherwise wouldn't (which txes of the block you still need), but I think it's not really possibly to abuse this, because creating valid blocks we'd
<theStack> larryruane: hm is it even possible to mix different types within an INV? (i have to make myself more familiar with the protocol messages...)
<dergoegge> in the interest of time lets move on: What do you think of Gleb’s comments on the usage of sendrawtransaction? Can you think of other exceptions in which a blocksonly node would still want to download compact blocks?
<jnewbery> but we only send sendcmpct(hb=true) if the peer is the first to provide a valid block at the tip. It's in the BlockChecked callback in the validation interface
<lightlike> dergoegge: if a node in blocksonly mode somehow receives up-to-date txes from somewhere else. I don't really think that the scenario by gleb sounds very probable.