From 6e14b9637ae0b097de1b4b1bcf07ccb2c9f5f048 Mon Sep 17 00:00:00 2001 From: "David A. Harding" Date: Mon, 31 Jul 2023 16:15:23 -1000 Subject: [PATCH] CH09-10: edits for Murchandamus feedback - Mention an example of Bitcoin Core sending a BIP151 transacation in advance, alas it's the only case implemented. - Mention that FIBRE is software (since Matt's main network for it was shut down) - Add fRelay to the node announcement message. We've only had it for 11 years. - Clarify descriptions mention the genesis block as part of the block chain - Mention that BIP157/8 is not able to relay unconfirmed transactions - Update assertion that the mempool is only stored in memory (on Bitcoin Core, it is now written to disk on shutdown; on libbitcoin, it's always written to disk) - HUGE FIX: correct inverted enumerator and denominator on feerates. So embarrasing! --- ch08.asciidoc | 53 ++++++++++++++++++++++------------------------ chapters/fees.adoc | 46 ++++++++++++++++++++-------------------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/ch08.asciidoc b/ch08.asciidoc index e23b73b5..df6bc13f 100644 --- a/ch08.asciidoc +++ b/ch08.asciidoc @@ -135,8 +135,7 @@ 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. +allows a peer to instead send a short 6-byte identifier for each 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 @@ -144,7 +143,8 @@ 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 the transactions that appear in the block, it can include a copy of -those transactions in the compact block. +those transactions in the compact block. For example, Bitcoin Core +always sends a block's coinbase transaction. 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 @@ -191,7 +191,7 @@ quickly announcing blocks). // released into the public domain by Nicolas Dorier [[bip152_illustration]] -.BIP152 modes compared (from BIP152) +.BIP152 modes compared (from BIP152). They grey bar indicates the time it takes the node to validate the block image::images/bip152.png["BIP152"] The names of the two methods (which are taken from BIP152) can be a bit @@ -262,7 +262,7 @@ miners and mining pools. 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 developer Matt -Corallo. FIBRE is a UDP-based relay network that relays blocks within a +Corallo. FIBRE is software that allows operating a UDP-based relay network that relays blocks within a network of nodes. FIBRE implements FEC and the _compact block_ optimization to further reduce the amount of data transmitted and the network latency. @@ -285,12 +285,13 @@ transmitting a +version+ message, which contains basic identifying information, including: +Version+:: The Bitcoin P2P protocol version the client "speaks" (e.g., 70002) -+nLocalServices+:: A list of local services supported by the node, currently just +NODE_NETWORK+ ++nLocalServices+:: A list of local services supported by the node +nTime+:: The current time +addrYou+:: The IP address of the remote node as seen from this node +addrMe+:: The IP address of the local node, as discovered by the local node +subver+:: A sub-version showing the type of software running on this node (e.g., pass:[/Satoshi:0.9.2.1/]) +BestHeight+:: The block height of this node's blockchain ++fRelay+:: A field added by BIP37 for requesting not to receive unconfirmed transactions (See http://bit.ly/1qlsC7w[GitHub] for an example of the +version+ network message.) @@ -438,11 +439,11 @@ valid blockchain with the most proof of work. ((("blocks", "genesis block")))((("genesis block")))((("blockchain (the)", "genesis block")))Full nodes -independently process every block, starting with the very first +independently process every block, starting after the very first block (genesis block) and building up to the latest known block in the network. A full node can independently and authoritatively -verify any transaction without recourse or reliance on any other node or -source of information. The full node relies on the network to +verify any transaction. +The full node relies on the network to receive updates about new blocks of transactions, which it then verifies and incorporates into its local view of which scripts control which bitcoins, called the set of _unspent transaction outputs_ (UTXOs). @@ -467,7 +468,7 @@ command +getpeerinfo+ as we saw earlier; for example, +/Satoshi:24.0.1/+. node will do once it connects to peers is try to construct a complete chain of block headers. If it is a brand-new node and has no blockchain at all, it only knows one block, the genesis block, which is statically embedded in -the client software. Starting with block #0 (the genesis block), the new +the client software. Starting after block #0 (the genesis block), the new node will have to download hundreds of thousands of blocks to synchronize with the network and reestablish the full blockchain. @@ -492,7 +493,7 @@ have. In parallel, the node will begin requesting the blocks for each header it previously received using a +getdata+ message. The node will request -different blocks from each of its peers, which allows it to drop +different blocks from each of its selected peers, which allows it to drop connections to peers that are significantly slower than the average in order to find newer (and possibly faster) peers. @@ -513,7 +514,7 @@ gradually built up, more blocks are requested and received, and the process continues until the node catches up to the rest of the network. This process of comparing the local blockchain with the peers and -retrieving any missing blocks happens any time a node goes offline for +retrieving any missing blocks happens any time a node has been offline for an extended period of time. [[spv_nodes]] @@ -529,7 +530,7 @@ blockchain. These types of clients are called SPV clients or lightweight clients. SPV clients download only the block headers and do not download the -transactions included in each block. The resulting chain of blocks, +transactions included in each block. The resulting chain of headers, without transactions, is about 10,000 times smaller than the full blockchain. SPV clients cannot construct a full picture of all the UTXOs that are available for spending because they do not know about all the @@ -549,7 +550,7 @@ a dozen other "23 Church Street" addresses in the city and whether this is the right one. The mapless tourist's best chance is to ask enough people and hope some of them are not trying to mug him. -SPV verifies transactions by reference to their _depth_ in the blockchain instead of their _height_. Whereas a full node will construct a fully verified chain of thousands of blocks and millions of transactions reaching down the blockchain (back in time) all the way to the genesis block, an SPV node will verify the proof of work of all blocks (but not whether the blocks and all of their transactions are valid) and link that chain to the transaction of interest. +SPV verifies transactions by reference to their _depth_ in the blockchain. Whereas a full node will construct a fully verified chain of thousands of blocks and millions of transactions reaching down the blockchain (back in time) all the way to the genesis block, an SPV node will verify the proof of work of all blocks (but not whether the blocks and all of their transactions are valid) and link that chain to the transaction of interest. For example, when examining a transaction in block 800,000, a full node verifies all 800,000 blocks down to the genesis block and builds a full @@ -591,7 +592,7 @@ node. A full node verifies a transaction by checking the entire chain of thousands of blocks below it in order to guarantee that the UTXO exists and is not spent, whereas an SPV client only proves that a transaction -exists and checks how deep the block containing that transaction is +exists and checks that the block containing that transaction is buried by a handful of blocks above it. ==== @@ -614,7 +615,7 @@ node, so developers have looked for other ways to solve the problem. Shortly after the introduction of SPV/lightweight clients, Bitcoin developers added a feature called _bloom filters_ in an attempt to -reduce the bandwdith that SPV clients needed to use to learn about their +reduce the bandwidth that SPV clients needed to use to learn about their incoming and outgoing transactions. Bloom filters allow SPV clients to receive a subset of the transactions without directly revealing precisely which addresses they are @@ -856,10 +857,12 @@ weren't created by the client. They can even download each matching block from a different peer, making it harder for full nodes to connect transactions belonging to a single client across multiple blocks. -This idea for server-generated filters doesn't offer perfect privacy and +This idea for server-generated filters doesn't offer perfect privacy, it still places some costs on full nodes (and it does require SPV -clients use more bandwidth for the block download), but it is much more -private and reliable than BIP37 client-requested bloom filters. +clients use more bandwidth for the block download), and the filters can +only be used for confirmed transactions (not unconfirmed transactions), +but it is much more private and reliable than BIP37 client-requested +bloom filters. After the description of the original idea based on bloom filters, developers realized there was a better data structure for @@ -1080,7 +1083,7 @@ the SipHash function we'll use for compact block filters. The details of the algorithm used are described in BIP158, but the gist is that each output script is reduced to a 64 bit commitment using -SipHash and some arthritic operations. You can think of this as +SipHash and some arithmetic operations. You can think of this as taking a set of large numbers and truncating them to shorter numbers, a process that loses data (so it's called _lossy encoding_). By losing some information, we don't need to store as much information later, @@ -1216,12 +1219,6 @@ of a parent transaction triggers a cascade reconstruction of an entire chain of interdependent transactions by re-uniting the orphans with their parents all the way down the chain. -Both the mempool and orphan pool (where implemented) are stored -in local memory and are not saved on persistent storage; rather, they -are dynamically populated from incoming network messages. When a node -starts, both pools are empty and are gradually populated with new -transactions received on the network. - Some implementations of the Bitcoin also maintain an UTXO database, which is the set of all unspent outputs on the blockchain. This represents a different set of data from the mempool. Unlike the @@ -1234,8 +1231,8 @@ table on persistent storage. Whereas the mempool and orphan pools represent a single node's local perspective and might vary significantly from node to node depending upon when the node was started or restarted, the UTXO database represents -the emergent consensus of the network and therefore will vary little -between nodes. Furthermore, the mempool and orphan pools only +the emergent consensus of the network and therefore will not usually +vary between nodes. Furthermore, the mempool and orphan pools only contain unconfirmed transactions, while the UTXO database only contains confirmed outputs. diff --git a/chapters/fees.adoc b/chapters/fees.adoc index 2a7abeb1..3c8f22c2 100644 --- a/chapters/fees.adoc +++ b/chapters/fees.adoc @@ -77,10 +77,7 @@ means that, even though it's possible to pay the fee in a different transaction, it's most efficient (and thus cheapest) to pay the fee in a single transaction. -Those technicalities leads us to design Bitcoin so that spenders are -normally responsible for fees. - -That's not always what's most convenient for the situation. In Bitcoin, +In Bitcoin, the fee is a bid and the amount paid contributes to determining how long it will take the transaction to confirm. Both spenders and receivers of a payment typically have an interest in having it confirming quickly, so @@ -103,31 +100,33 @@ Each transaction only pays a single fee--it doesn't matter how large the transaction is. However, the larger transactions become, the fewer of them a miner will be able to fit in a block. For that reason, miners evaluate transactions the same way you might comparison shop between -several equivalent items at the market: they divide quantity by price. -Whereas you might divide the weight of several different bags of rice by -their cost to find the lowest price per weight (best deal), miners -divide the size of a transaction (also called its weight) by the fee to +several equivalent items at the market: they divide the price by the +quantity. + +Whereas you might divide the cost of several different bags of rice by +each bag's weight to find the lowest price per weight (best deal), miners +divide the fee of a transaction by its size (also called its weight) to find the highest fee per weight (most revenue). In Bitcoin, we use the term _fee rate_ for a transaction's size divided by weight. Due to changes in Bitcoin over the years, fee rate can be expressed in different units: -- Bytes/BTC (a legacy unit rarely used anymore) -- Kilobytes/BTC (a legacy unit rarely used anymore) -- vBytes/BTC (rarely used) -- Kilo-vByte/BTC (used mainly in Bitcoin Core) -- vByte/satoshi (most commonly used today) -- weight/satoshi (also commonly used today) +- BTC/Bytes (a legacy unit rarely used anymore) +- BTC/Kilobytes (a legacy unit rarely used anymore) +- BTC/vbytes (rarely used) +- BTC/Kilo-vbyte (used mainly in Bitcoin Core) +- Satoshi/vbyte (most commonly used today) +- Satoshi/weight (also commonly used today) -We recommend either the vByte/sat or weight/sat units for displaying +We recommend either the sat/vbyte or sat/weight units for displaying fee rates. [WARNING] ==== Be careful accepting input for fee rates. If a user copy and pastes a -fee rate printed in one enumerator into a field using a different +fee rate printed in one denominator into a field using a different enumerator, they could overpay fees by 1,000 times. If they instead -switch the denominator, they could theoretically overpay by 100,000,000 +switch the enumerator, they could theoretically overpay by 100,000,000 times. Wallets should make it hard for the user to pay an excessive fee rate and may want to prompt the user to confirm any fee rate that was not generated by the wallet itself using a trusted data source. @@ -198,8 +197,8 @@ To increase the fee of a transaction using RBF fee bumping, you create a conflicting version of the transaction which pays a higher fee. Two or more transactions are considered to be _conflicting transactions_ if only one of them can be included in a valid block chain, forcing a miner -to chose only one of them. Conflicts occur when two or more transaction -both try to spend one of the same UTXOs, i.e. they each include an input +to chose only one of them. Conflicts occur when two or more transactions +each try to spend one of the same UTXOs, i.e. they each include an input that has the same outpoint (reference to the output of a previous transaction). @@ -396,7 +395,7 @@ less disruptive to some merchants than RBF. The primary disadvantage of CPFP compared to RBF is that CPFP typically uses more block space. In RBF, a fee bump transaction is often the same -size as the transaction it replaces. In CPFP, a fee bump is a whole +size as the transaction it replaces. In CPFP, a fee bump adds a whole separate transaction. Using extra block space requires paying extra fees beyond the the cost of the fee bump. @@ -533,7 +532,7 @@ transactions at a point in the protocol when trust isn't needed, allowing either of them to broadcast one of those transactions at a later time when the other party may not want to (or be able to) fulfill its obligations. The problem with this approach is that the -transactions might need to be broadcast far in the future, beyond any +transactions might need to be broadcast at an unknown time, far in the future, beyond any reasonable ability to estimate an appropriate fee rate for the transactions. @@ -560,7 +559,8 @@ outputs, one to each of them. Mallory broadcasts that transaction and uses her output to attach either 25 child transactions or any smaller number of child transactions equaling 100,000 vbytes in size. Without carve-out, Bob would be unable to attach another child transaction to -his output for CPFP fee bumping. With carve-out, he can do that as long +his output for CPFP fee bumping. With carve-out, he can spend one of +the two outputs in the transaction, the one that belongs to me, as long as his child transaction is less than 1,000 vbytes in size (which should be more than enough space). @@ -595,7 +595,7 @@ large fee by underspending the inputs. That means that you must account for all inputs, if necessary by creating change, or you will end up giving the miners a very big tip! -For example, if you consume a 20-bitcoin UTXO to make a 1-bitcoin +For example, if you spend a 20-bitcoin UTXO to make a 1-bitcoin payment, you must include a 19-bitcoin change output back to your wallet. Otherwise, the 19-bitcoin "leftover" will be counted as a transaction fee and will be collected by the miner who mines your