This week’s newsletter describes how the selfish mining danger threshold can be calculated, summarizes an idea about preventing filtering of high feerate transactions, seeks feedback about a proposed change to BIP390 musig() descriptors, and announces a new library for encrypting descriptors. Also included are our regular sections with the summary of a Bitcoin Core PR Review Club, announcements of new releases and release candidates, and descriptions of recent changes to popular Bitcoin infrastructure projects.

News

  • Calculating the selfish mining danger threshold: Antoine Poinsot posted to Delving Bitcoin an expansion of the math from the 2013 paper that gave the selfish mining attack its name (although the attack was previously described in 2010). He also provided a simplified mining and block relay simulator that allows experimenting with the attack. He focuses on reproducing one of the conclusions of the 2013 paper: that a dishonest miner (or a cartel of well-connected miners) controlling 33% of the total network hashrate, with no additional advantages, can become marginally more profitable on a long term basis than the miners controlling 67% of the hashrate. This is achieved by the 33% miner selectively delaying the announcement of some of the new blocks it finds. As the dishonest miner’s hashrate increases above 33%, it becomes even more profitable until it exceeds 50% hashrate and can prevent its competitors from keeping any new blocks on the best blockchain.

    We did not carefully review Poinsot’s post, but his approach appeared sound to us and we would recommend it to anyone interested in validating the math or gaining a better understanding of it.

  • Relay censorship resistance through top mempool set reconciliation: Peter Todd posted to the Bitcoin-Dev mailing list about a mechanism that would allow nodes to drop peers that are filtering high-feerate transactions. The mechanism depends on cluster mempool and a set reconciliation mechanism such as that used by erlay. A node would use cluster mempool to calculate its most profitable set of unconfirmed transactions that could fit within (for example) 8,000,000 weight units (a maximum of 8 MB). Each of the node’s peers would also calculate their top 8 MWU of unconfirmed transactions. Using a highly efficient algorithm, such as minisketch, the node would reconcile its set of transactions with each of its peers. In doing so, it would learn exactly what transactions each peer has in the top of its mempool. Then the node would periodically drop the connection to whichever peer had the least profitable mempool on average.

    By dropping the least profitable connections, the node would eventually find peers that were least likely to filter out high-feerate transactions. Todd mentioned that he hopes to work on an implementation after cluster mempool support is merged into Bitcoin Core. He credited the idea to Gregory Maxwell and others; Optech first mentioned the underlying idea in Newsletter #9.

  • Updating BIP390 to allow duplicate participant keys in musig() expressions: Ava Chow posted to the Bitcoin-Dev mailing list to ask if anyone objected to updating BIP390 to allow musig() expressions in output script descriptors to contain the same participant public key more than once. This would simplify implementation and is explicitly allowed by the BIP327 specification of MuSig2. As of this writing, no one has objected, and Chow has opened a pull request to change the BIP390 specification.

  • Descriptor encryption library: Josh Doman posted to Delving Bitcoin to announce a library he’s built that encrypts the sensitive parts of an output script descriptor or miniscript to the public keys contained within it. He describes what information is needed to decrypt:

    • If your wallet requires 2-of-3 keys to spend, it will require exactly 2-of-3 keys to decrypt.

    • If your wallet uses a complex miniscript policy like “Either 2 keys OR (a timelock AND another key)”, encryption follows the same structure, as if all timelocks and hash-locks are satisfied.

    This differs from the encrypted descriptor backup scheme discussed in Newsletter #351, in which knowledge of any public key contained within the descriptor allows decryption of the descriptor. Doman argues that his scheme provides better privacy for cases where the encrypted descriptor is being backed up to a public or semi-public source, such as a blockchain.

Bitcoin Core PR Review Club

In this monthly section, we summarize a recent Bitcoin Core PR Review Club meeting, highlighting some of the important questions and answers. Click on a question below to see a summary of the answer from the meeting.

Separate UTXO set access from validation functions is a PR by TheCharlatan that allows calling validation functions by passing just the required UTXOs, instead of requiring the complete UTXO set. It is part of the bitcoinkernel project, and is an important step to make the library more usable for full-node implementations that do not implement a UTXO set, such as Utreexo or SwiftSync nodes (see Newsletter #349).

In the first 4 commits, this PR reduces coupling between transaction validation functions and the UTXO set by requiring the caller to first fetch the Coins or CTxOuts they require and passing those to the validation function, instead of letting the validation function access the UTXO set directly.

In subsequent commits, the dependency of ConnectBlock() on the UTXO set is removed entirely by carving out the remaining logic that requires UTXO set interaction into a separate SpendBlock() method.

  • Why is carving out the new SpendBlock() function from ConnectBlock() helpful for this PR? How would you compare the purpose of the two functions?

    The ConnectBlock() function originally performed both block validation and UTXO set modifications. This refactor splits these responsibilities: ConnectBlock() is now only responsible for validation logic that doesn’t require the UTXO set, while the new SpendBlock() function handles all UTXO set interactions. This allows a caller to use ConnectBlock() to do block validation without a UTXO set. 

  • Do you see another benefit of this decoupling, besides allowing kernel usage without a UTXO set?

    Besides enabling kernel usage for projects without a UTXO set, this decoupling makes the code easier to test in isolation and simpler to maintain. One reviewer also notes that removing the need for UTXO set access opens the door for validating blocks in parallel, which is an important feature of SwiftSync. 

  • SpendBlock() takes a CBlock block, CBlockIndex pindex and uint256 block_hash parameter, all referencing the block being spent. Why do we need 3 parameters to do that?

    Validation code is performance-critical, it affects important parameters such as block propagation speed. Calculating the block hash from a CBlock or CBlockIndex is not free, because the value is not cached. For that reason, the author decided to prioritize performance by passing an already calculated block_hash as a separate parameter. Similarly, the pindex could be fetched from the block index, but this would involve an additional map lookup that is not strictly necessary.
    Note: the author later changed the approach, removing the block_hash performance optimization. 

  • The first commits in this PR refactor CCoinsViewCache out of the function signature of a couple of validation functions. Does CCoinsViewCache hold the entire UTXO set? Why is that (not) a problem? Does this PR change that behaviour?

    CCoinsViewCache does not hold the entire UTXO set; it is an in-memory cache that sits in front of CCoinsViewDB, which stores the full UTXO set on disk. If a requested coin is not in the cache, it must be fetched from disk. This PR does not change this caching behavior itself. By removing CCoinsViewCache from function signatures, it makes the UTXO dependency explicit, requiring the caller to fetch coins before calling the validation function. 

Releases and release candidates

New releases and release candidates for popular Bitcoin infrastructure projects. Please consider upgrading to new releases or helping to test release candidates.

Notable code and documentation changes

Notable recent changes in Bitcoin Core, Core Lightning, Eclair, LDK, LND, libsecp256k1, Hardware Wallet Interface (HWI), Rust Bitcoin, BTCPay Server, BDK, Bitcoin Improvement Proposals (BIPs), Lightning BOLTs, Lightning BLIPs, Bitcoin Inquisition, and BINANAs.

  • Bitcoin Core #32406 uncaps the OP_RETURN output size limit (standardness rule) by raising the default -datacarriersize setting from 83 to 100,000 bytes (the maximum transaction size limit). The -datacarrier and -datacarriersize options remain, but are marked as deprecated and are expected to be removed in an undetermined future release. Additionally, this PR also lifts the one-per-transaction policy restriction for OP_RETURN outputs, and the size limit is now allocated across all such outputs in a transaction. See Newsletter #352 for additional context on this change.

  • LDK #3793 adds a new start_batch message that signals peers to treat the next n (batch_size) messages as a single logical unit. It also updates PeerManager to rely on this for commitment_signed messages during splicing, rather than adding a TLV and a batch_size field to each message in the batch. This is an attempt to allow additional LN protocol messages to be batched rather than only commitment_signed messages, which is the only batching defined in the LN specification.

  • LDK #3792 introduces initial support for v3 commitment transactions (see Newsletter #325) that rely on TRUC transactions and ephemeral anchors, behind a test flag. A node now rejects any open_channel proposal that sets a non-zero feerate, ensures that it never initiates such channels itself, and stops automatically accepting v3 channels to first reserve a UTXO for later fee-bumping. The PR also lowers the per-channel HTLC limit from 483 to 114 because TRUC transactions must remain under 10 kvB.

  • LND #9127 adds a --blinded_path_incoming_channel_list option to the lncli addinvoice command, allowing a recipient to embed one or more (for multiple hops) preferred channel IDs for the payer to attempt to forward through on a blinded path.

  • LND #9858 begins signaling the production feature bit 61 for the RBF cooperative close flow (see Newsletter #347) to properly enable interoperability with Eclair. It retains the staging bit 161 to maintain interoperability with nodes testing the feature.

  • BOLTs #1243 updates the BOLT11 specification to indicate that a reader (sender) must not pay an invoice if a mandatory field, such as p (payment hash), h (description hash), or s (secret), has an incorrect length. Previously, nodes could ignore this issue. This PR also adds a note to the Examples section explaining that Low R signatures, even if they save one byte of space, are not enforced in the specification.

Want more?

For more discussion about the topics mentioned in this newsletter, join us for the weekly Bitcoin Optech Recap on Riverside.fm at 16:30 UTC on June 17. The discussion is also recorded and will be available from our podcasts page.