From 9142816196609e0c40c746b2695cc47112f4c6ab Mon Sep 17 00:00:00 2001 From: "David A. Harding" Date: Thu, 11 May 2023 09:46:25 -1000 Subject: [PATCH] CH10: add compact block relay & update relay networks - Describe BIP152 compact block relay - Describe why we still need relay networks (what they do that BIP152 can't) - Drop FALCON relay (never used, AFAIK) - Minor updates to relay section --- ch08.asciidoc | 183 +++++++++++++++++++++++++++++++++++-------- images/bip152.png | Bin 0 -> 17398 bytes images/race1.dot | 37 +++++++++ images/race1.dot.png | Bin 0 -> 1898 bytes 4 files changed, 189 insertions(+), 31 deletions(-) create mode 100644 images/bip152.png create mode 100644 images/race1.dot create mode 100644 images/race1.dot.png diff --git a/ch08.asciidoc b/ch08.asciidoc index 4348dcb3..1dc91977 100644 --- a/ch08.asciidoc +++ b/ch08.asciidoc @@ -102,51 +102,172 @@ protocols. These other protocol nodes are mostly pool mining nodes (see <>) and lightweight wallet clients, which do not carry a full copy of the blockchain. -=== Bitcoin Relay Networks -((("Bitcoin network", "Bitcoin Relay Networks")))((("relay -networks")))While the Bitcoin P2P network serves the general needs of a -broad variety of node types, it exhibits too high network latency for -the specialized needs of Bitcoin mining nodes. +=== Compact Block Relay -((("propagation", "relay networks and")))Bitcoin miners are engaged in a -time-sensitive competition to solve the Proof-of-Work problem and extend -the blockchain (see <>). While participating in this -competition, Bitcoin miners must minimize the time between the -propagation of a winning block and the beginning of the next round of -competition. In mining, network latency is directly related to profit -margins. +When a miner finds a new block, they announce it to the Bitcoin network +(which includes other miners). The miner who found that block can start +building on top of it immediately; all other miners who haven't learned +about the block yet will continue building on top of the previous block +until they do learn about it (and, ideally, they also validate it). -A _Bitcoin Relay Network_ is a network that attempts to minimize the -latency in the transmission of blocks between miners. The original +If, before they learn about the new block, one of those other +miners creates a block, their block will be in competition with the +first miner's new block. Only one of the blocks will ever be included +in the blockchain used by all full nodes, and miners only get paid for +blocks that are widely accepted. + +Whichever block has a second block built on top of it first wins (unless +there's another near-tie), which is called a _block-finding race_. +Block-finding races give the advantage to the largest miners, so they +act in opposition to Bitcoin's essential decentralization. To prevent +block-finding races and allow miners of any size to participate equally +in the lottery that is Bitcoin mining, it's extremely useful to minimize +the time between when one miner announces a new block and when other +miners receive that block. + +.A blockchain fork requiring a mining race +image::images/race1.dot.png["Mining race"] + +In 2015, a new version of Bitcoin Core added a feature called +_compact block relay_ (specified in BIP152) that allows transferring new +blocks both faster and with less bandwidth. + +As background, full nodes that relay unconfirmed transactions also store +many of those transactions in their mempools (see <>). When +some of those transactions are confirmed in a new block, the node +doesn't need to receive a second copy of those transactions. + +Instead of receiving redundant unconfirmed transactions, compact blocks +allows a peer that believes your node already has a transaction in that +block to instead send a short 6-byte identifier for that transaction. +When your node receives a compact block with one or more identifiers, it +checks its mempool for those transactions and uses them if they are +found. For any transaction that isn't found in your local node's +mempool, your node can send a request to the peer for a copy. + +Conversely, if the remote peer believes your node's mempool doesn't have +some of transactions that appear in the block, it can include a copy of +those transaction in the compact block. + +If the remote peer guesses correctly about what transactions your node +has in its mempool, and which it does not, it will send a block nearly +as efficiently as is theoretically possible (for a typical block, it'll +be between 97% to 99% efficient). + +[TIP] +==== +Compact block relay does not decrease the size of blocks. It just +prevents the redundant transfer of information that a node already has. +When a node doesn't previously have information about a block, for +example when a node is first started, it must receive complete copies of +each block. +==== + +There are two modes that Bitcoin Core currently implements for sending +compact blocks: + +Low-bandwidth mode:: + When your node requests that a peer use low-bandwidth mode (the default), + that peer will tell your node the 32-byte identifier (header hash) of a + new block but will not send your node any details about it. If your + node acquires that block first from another source, this avoids + wasting any more of your bandwidth acquiring a redundant copy of that + block. If your node does need the block, it will request a compact + block. + +High-bandwidth mode:: + When your node requests that a peer use high-bandwidth mode, that peer + will send your node a compact block for a new block even before it has + fully verified that the block is valid. The only validation the peer + will perform is ensuring that the block's header contains the correct + amount of proof of work. Since proof of work is expensive to generate + (about $150,000 USD at the time of writing), it's unlikely that a + miner would fake it just to waste the bandwidth of relay nodes. + Skipping validation before relay allows new blocks to travel across + the network with minimal delays at each hop. ++ +The downside of high-bandwidth node is that your node is likely to +receive redundant information from each high-bandwidth peer it chooses. +As of this writing, Bitcoin Core currently only asks three peers to use +high-bandwidth mode (and it tries to choose peers that have a history of +quickly announcing blocks). + +// released into the public domain by Nicolas Dorier +.BIP152 modes compared (from BIP152) +image::images/bip152.png["BIP152"] + +The names of the two methods (which are taken from BIP152) can be a bit +confusing. Low-bandwidth mode saves bandwidth by not sending blocks in +most cases. High-bandwidth mode uses more bandwidth than low-bandwidth +mode but, in most cases, much less bandwidth than was used for block +relay before compact blocks were implemented. + +=== Private Block Relay Networks + +Although compact blocks go a long way towards minimizing the latency +of block propagation, it's possible to minimize latency further. Unlike +compact blocks, though, the other solutions involve tradeoffs that +make them unavailable or unsuitable for the public P2P relay network. +For that reason, there has been experimentation with private relay +networks for blocks. + +One simple technique is to pre-select a route between endpoints. For +example, a relay network with servers running in datacenters near major +trans-oceanic fiber optic lines might be able to forward new blocks +faster than waiting for the block to arrive at the node run by some home +user many kilometers away from the fiber optic line. + +Another, more complex technique, is Forward Error Correction (FEC). +This allows a compact block message to be split into several parts, with +each part having extra data appended. If any of the parts isn't +received, that part can be reconstructed from the parts that are +received. Depending on the settings, up to several parts may be +reconstructed if they are lost. + +FEC avoids the problem of a compact block (or some parts of it) not +arriving due to problems with the underlying network connection. +Those problems frequently occur but we mostly don't notice them +because we mostly use protocols that automatically re-request the +missing data. However, requesting missing data triples the time to +receive it. For example: + +1. Alice sends some data to Bob +2. Bob doesn't receive the data (or it is damaged). Bob re-requests + the data from Alice +3. Alice sends the data again + +A third technique is to assume all nodes receiving the data have +almost all of the same transactions in their mempool, so they can all +accept the same compact block. That not only saves us time computing +a compact block at each hop but it means that all each hop can simply +relay the FEC packets to the next hop even before validating them. + +The tradeoff for each of the above methods is that they work well with +centralization but not in a decentralized network where individual nodes +can't trust other nodes. Servers in datacenters cost money and can +often be accessed by operators of the datacenter, making them less +trustworthy than a secure home computer. Relaying data before +validating makes it easy to waste bandwidth, so it can only reasonably +be used on a private network where there's some level of trust and +accountability between parties. + +The original http://www.bitcoinrelaynetwork.org[Bitcoin Relay Network] was created by -core developer Matt Corallo in 2015 to enable fast synchronization of +developer Matt Corallo in 2015 to enable fast synchronization of blocks between miners with very low latency. The network consisted of -several specialized nodes hosted on the Amazon Web Services +several Virtual Private Servers (VPSes) hosted on infrastructure around the world and served to connect the majority of miners and mining pools. ((("Fast Internet Bitcoin Relay Engine (FIBRE)")))((("Compact Block optimization")))The original Bitcoin Relay Network was replaced in 2016 with the introduction of the _Fast Internet Bitcoin Relay Engine_ or -http://bitcoinfibre.org[_FIBRE_], also created by core developer Matt +http://bitcoinfibre.org[_FIBRE_], also created by developer Matt Corallo. FIBRE is a UDP-based relay network that relays blocks within a -network of nodes. FIBRE implements _compact block_ optimization to +network of nodes. FIBRE implements FEC and the _compact block_ optimization to further reduce the amount of data transmitted and the network latency. -((("Falcon Relay Network")))Another relay network (still in the proposal -phase) is http://www.falcon-net.org/about[_Falcon_], based on research -at Cornell University. Falcon uses "cut-through-routing" instead of -"store-and-forward" to reduce latency by propagating parts of blocks as -they are received rather than waiting until a complete block is -received. - -Relay networks are not replacements for Bitcoin's P2P network. Instead -they are overlay networks that provide additional connectivity between -nodes with specialized needs. Like freeways are not replacements for -rural roads, but rather shortcuts between two points with heavy traffic, -you still need small roads to connect to the freeways. - === Network Discovery ((("Bitcoin network", "extended network discovery", diff --git a/images/bip152.png b/images/bip152.png new file mode 100644 index 0000000000000000000000000000000000000000..0d2b07d3988c77a0155e22df5b2264f0f747d158 GIT binary patch literal 17398 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 Kyt)0* B; + B -> C; + B -> C1; + C -> D [style=dashed]; + C1 -> D1 [style=dashed]; + + { + rank=same; + A; + } + { + rank=same; + B; + } + { + rank=same; + C; + C1; + } + { + rank=same; + D; + D1; + } +} + diff --git a/images/race1.dot.png b/images/race1.dot.png new file mode 100644 index 0000000000000000000000000000000000000000..f638a71dbeabe32dc14ad1a16c7403ca26b48e64 GIT binary patch literal 1898 zcmV-w2bK7VP)I1qKEN2L}fT2nY!Y2?`1d3kwSk4Gj(s4i66x5D*X%5fKs+ z5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM92^`T9v&bdAR!?kA|fIqBO@dvBqk;% zDJdx`Dk>~2EG{lCFE1}JFfcMQGBYzXH8nLhHa0gmH#j&rIXO8xIyyT$J3c->KR-V} zKtMr3K|(@8L_|bIMMX$RNJ&XaN=iygOG`{lOifKqPEJlwPft)#P*G7)Qc_Y=Q&Ut_ zR8>_~R#sM8T3TFOTwPsVWo2b%W@cw+XKHF{Y;0_8ZEbFDZg6mLadB~UbaZufb#``k zcXxMue0+a@e}RF4f`WpBgM);GgoucUi;Ihmjg5|uj*pLzkdTm+l$4c~m6({AnVFfI znwp)Rot~bapP!$gprE0lp`xOqq@<*!rKP5(rl+T;sHmu^si~@}s;sQ6uCA`HudlGM zu(GnUv$M0bw6waqy1To(zP`S{zrVu5!o$PE#KgqK#l^dCU$;rve%F4{l%+1Zs z&d$!y&(F}%(9_e?)YR0~)z#P6*Vx$D+1c6L+}z#W-QM2b-{0Tj;^O1ulq( z=H}<;=jiC@>FMd}>gwz3>+S9B?(XjI@9*&N@bU5S^78WY^Yird^!4@i_V)Jo_xJet z`1$$y`uh6&`}_R-{Qdp?{{H^||Nq8Ph~@wQ00DGTPE)FO<&uy90004EOGiYtGY(oy z000E(Nkli!8oKJJ!^PcydcNIKH zp^6G%08D@hFv+KARJ;hYf>dq1n6Mu4!ixlPYPRK>NWY+l3^GBE7(3E0s3AO=c#G~M zFaaj!GKq4)MEyR-Om2Vr%92%^f5e?hl#?0TpZfLw-|eUeb0#_3emwbS?pbOaHzrfz zdHn|OpaI;NjG(8x&n9#ltU*_CV={^mgWSFWEiA{;x_R7~Or%!;465k}Jz98o$Vb-x zDPLT9abR*+S{N-#VTmj5QqTBqIW>-bJR^QE9*Lak@BfXvDB6)vWb4IBw5;p*Tqf6? z7~9v@)~338&lI zR@RLa#bp1Pg#Gg;6I4#ZwPqXSPk6pr28G_ux!@|I6p5)8PB<$5y*l0+hr#`K(B?dc}l8u2W zKH*MAoGcA!#-5BkIuEPY=;PJi2DJXjX!^RFp>^H!EQ zOg1C5;j?IA@5$?9yv1c26M`XL^N;_}IM$&|(mMuZQ*a8H$eAQXk<2y@3nqEBBG=qK z=X@pyxIEgJ!9fwOc61WPPG;;-6x|%027i)alAd_(z`T=XLZg@cw+o6-c45M#Y3<>g z1-9Q!H~J@VU~;SQ_V2#YT2G$KQzReHVa9?z}V9 zy9TZA{R^1n&czX*o3x<3H3I7PQ2(7w=h)g^6&4cd0g2k*3#5S zTAYcB#~r1*GO0?qBe~cvKC-V%0yR2 zndnNhk6DlVB7vBd=gZ8*A`(6BrSuw``4*Un9{1}ea)oeC3B4bG(oDi_R%DXYh+E1} zHQs@`Q9*xX3n^A#DIpU()s60BGEnHMAE0hDsd$ZSk|Kx~T8mj4#YqF-v*lGd>pFe!BGq^gVE zzK@}9G|Pk`7QYvI1a+esCg}qpb1LmIts6};p|^g2U%kC;>PF3F@?cBgU%Tf|%x2<{ z{7D&^VE@0!fQbQSzyz286JUZ5lX{)PT#w02Y?43e)34w*{w4@&)39y9gg5(55ERz1 kab)6%^$surCRSzgA8U`9{loOz(*OVf07*qoM6N<$f}$6s?*IS* literal 0 HcmV?d00001