This week’s newsletter summarizes a discussion about allowing relay of transactions containing data in the taproot annex field and links to a draft BIP for silent payments. Also included is another entry in our limited weekly series about mempool policy, plus our regular sections summarizing a Bitcoin Core PR Review Club meeting, announcing new software releases and release candidates, and describing notable changes to popular Bitcoin infrastructure software.

News

  • Discussion about the taproot annex: Joost Jager posted to the Bitcoin-Dev mailing list a request for a change in the Bitcoin Core transaction relay and mining policy to allow storing arbitrary data in the taproot annex field. This field is an optional part of the witness data for taproot transactions. If present, signatures in taproot and tapscript must commit to its data (making it impossible for a third party to add, remove, or change) but it has no other defined purpose at present—it’s reserved for future protocol upgrades, especially soft forks.

    Although there have been previous proposals to define a format for the annex, these have not seen widespread acceptance and implementation. Jager proposed two formats (1, 2) that could be used to allow anyone to add arbitrary data to the annex in a way that would not significantly complicate later standardization efforts that might be bundled with a soft fork.

    Greg Sanders replied to ask what data Jager specifically wanted to store in the annex and described his own use for the annex in testing the LN-Symmetry protocol with the SIGHASH_ANYPREVOUT soft fork proposal using Bitcoin Inquisition (see Newsletter #244). Sanders also described a problem with the annex: in a multi-party protocol (such as a coinjoin), each signature only commits to the annex for the input containing that signature—not the annexes for other inputs in the same transaction. That means if Alice, Bob, and Mallory sign a coinjoin together, there’s no way Alice and Bob can prevent Mallory from broadcasting a version of the transaction with a large annex that delays its confirmation. Because Bitcoin Core and other full nodes don’t currently relay transactions that contain annexes, this is not a problem at present. Jager replied that he wants to store signatures from ephemeral keys for a type of vault that doesn’t require a soft fork, and he suggested that some previous work in Bitcoin Core could possibly address the problem with annex relay in some multiparty protocols.

  • Draft BIP for silent payments: Josie Baker and Ruben Somsen posted to the Bitcoin-Dev mailing list a draft BIP for silent payments, a type of reusable payment code that will produce a unique onchain address each time it is used, preventing output linking. Output linking can significantly reduce the privacy of users (including users not directly involved in a transaction). The draft goes into detail about the benefits of the proposal, its tradeoffs, and how software can effectively use it. Several insightful comments have already been posted on the PR for the BIP.

Waiting for confirmation #5: Policy for Protection of Node Resources

A limited weekly series about transaction relay, mempool inclusion, and mining transaction selection—including why Bitcoin Core has a more restrictive policy than allowed by consensus and how wallets can use that policy most effectively.

We started off our series by stating that much of Bitcoin’s privacy and censorship resistance stems from the decentralized nature of the network. The practice of users running their own nodes reduces central points of failure, surveillance, and censorship. It follows that one primary design goal for Bitcoin node software is high accessibility of running a node. Requiring each Bitcoin user to purchase expensive hardware, use a specific operating system, or spend hundreds of dollars per month in operational costs would very likely reduce the number of nodes on the network.

Additionally, a node on the Bitcoin network is a computer with internet connections to unknown entities that may launch a Denial of Service (DoS) attack by crafting messages that cause the node to run out of memory and crash, or spend its computational resources and bandwidth on meaningless data instead of accepting new blocks. As these entities are anonymous by design, nodes cannot predetermine whether a peer will be honest or malicious before connecting, and cannot effectively ban them even after an attack is observed. Thus, it is not just an ideal to implement policies that protect against DoS and limit the cost of running a full node, but an imperative.

General DoS protections are built into node implementations to prevent resource exhaustion. For example, if a Bitcoin Core node receives many messages from a single peer, it only processes the first one and adds the rest to a work queue to be processed after other peers’ messages. A node also typically first downloads a block header and verifies its Proof of Work (PoW) prior to downloading and validating the rest of the block. Thus, any attacker wishing to exhaust this node’s resources through block relay must first spend a disproportionately high amount of their own resources computing a valid PoW. The asymmetry between the huge cost for PoW calculation and the trivial cost of verification provides a natural way to build DoS resistance into block relay. This property does not extend to unconfirmed transaction relay.

General DoS protections don’t provide enough attack resistance to allow a node’s consensus engine to be exposed to input from the peer-to-peer network. An attacker attempting to craft a maximally computationally-intensive, consensus-valid transaction may send one like the 1MB “megatransaction” in block #364292, which took an abnormally long time to validate due to signature verification and quadratic sighashing. An attacker may also make all but the last signature valid, causing the node to spend minutes on their transaction, only to find that it is garbage. During that time, the node would delay processing a new block. One can imagine this type of attack being targeted at competing miners to gain a “head start” on the next block.

In an effort to avoid working on very computationally expensive transactions, Bitcoin Core nodes impose a maximum standard size and a maximum number of signature operations (or “sigops”) on each transaction, more restrictive than the block consensus limit. Bitcoin Core nodes also enforce limits on both ancestor and descendant package sizes, making block template production and eviction algorithms more effective and restricting the computational complexity of mempool insertion and deletion which require updating a transaction’s ancestor and descendant sets. While this means some legitimate transactions may not be accepted or relayed, those transactions are expected to be rare.

These rules are examples of transaction relay policy, a set of validation rules in addition to consensus which nodes apply to unconfirmed transactions.

By default, Bitcoin Core nodes do not accept transactions below the 1sat/vB minimum relay feerate (“minrelaytxfee”), do not verify any signatures before checking this requirement, and do not forward transactions unless they are accepted to their mempools. In a sense, this feerate rule sets a minimum “price” for network validation and relay. A non-mining node doesn’t ever receive fees – they are only paid to the miner who confirms the transaction. However, fees represent a cost to the attacker. Somebody who “wastes” network resources by sending an extremely high amount of transactions eventually runs out of money to pay the fees.

The Replace by Fee policy implemented by Bitcoin Core requires that the replacement transaction pay a higher feerate than each transaction it directly conflicts with, but also requires that it pay a higher total fee than all of the transactions it displaces. The additional fees divided by the replacement transaction’s virtual size must be at least 1sat/vB. In other words, regardless of the feerates of the original and replacement transactions, the new transaction must pay “new” fees to cover the cost of its own bandwidth at 1sat/vB. This fee policy is not primarily concerned with incentive compatibility. Rather, this incurs a minimum cost for repeated transaction replacements to curb bandwidth-wasting attacks, e.g. one that adds just 1 additional satoshi to each replacement.

A node that fully validates blocks and transactions requires resources including memory, computational resources, and network bandwidth. We must keep resource requirements low in order to make running a node accessible and to defend the node against exploitation. General DoS protections are not enough, so nodes apply transaction relay policies in addition to consensus rules when validating unconfirmed transactions. However, as policy is not consensus, two nodes may have different policies but still agree on the current chain state. Next week’s post will discuss policy as an individual choice.

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.

Allow inbound whitebind connections to more aggressively evict peers when slots are full is a PR by Matthew Zipkin (pinheadmz) that improves a node operator’s ability in certain cases to configure desired peers for the node. Specifically, if the node operator has whitelisted a potential inbound peer (for example, a light client controlled by the node operator), then without this PR, and depending on the node’s peer state, it’s possible that the node will deny this light client’s connection attempt.

This PR makes it much more likely that the desired peer will be able to connect to our node. It does this by evicting an existing inbound peer that, without this PR, would have been ineligible for eviction.

  • Why does this PR only apply to inbound peer requests?

    Our node initiates outbound connections; this PR modifies how the node reacts to an incoming connection request. Outbound nodes can be evicted, but that’s done with an entirely separate algorithm. 

  • What is the impact of the force parameter of SelectNodeToEvict() on the return value?

    Specifying force as true ensures that a non-noban inbound peer is returned, if one exists, even if it would otherwise be protected from eviction. Without the PR, it would not return a peer if they all are excluded (protected) from eviction. 

  • How is the function signature of EraseLastKElements() changed in this PR?

    It changed from being a void return function to returning the last entry that was removed from the eviction candidates list. (This “protected” node might be evicted if necessary.) However, as a result of discussion during the review club meeting, the PR was later simplified such that this function is no longer modified. 

  • EraseLastKElements used to be a templated function, but this PR removes the two template arguments. Why? Are there any downsides to this change?

    This function was and (with this PR) is being called with unique template arguments, so there is no need for the function to be templated. The PR’s changes to this function were reverted, so it’s still templated, because changing this would be beyond the scope of the PR. 

  • Suppose we pass a vector of 40 eviction candidates to SelectNodeToEvict(). Before and after this PR, what’s the theoretical maximum of Tor nodes that can be protected from eviction?

    Both with and without the PR, the number would be 34 out of 40, assuming they’re not noban and inbound. 

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.

  • Core Lightning 23.05.1 is a maintenance release for this LN implementation. Its release notes say, “this is a bugfix-only release which repairs several crashes reported in the wild. It is a recommended upgrade for anyone on v23.05.”

Notable code and documentation changes

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

  • Bitcoin Core #27501 adds a getprioritisedtransactions RPC that returns a map of all fee deltas created by the user with prioritisetransaction, indexed by txid. The map also indicates whether each transaction is present in the mempool. See also Newsletter #250.

  • Core Lightning #6243 updates the listconfigs RPC to put all configuration information in a single dictionary and also passes the state of all configuration options to restarted plugins.

  • Eclair #2677 increases the default max_cltv from 1,008 blocks (about one week) to 2,016 blocks (about two weeks). This extends the maximum permitted number of blocks until a payment attempt times out. The change is motivated by nodes on the network raising their reserved time window to address an expiring HTLC (cltv_expiry_delta) in response to high on-chain feerates. Similar changes have been merged to LND and CLN.

  • Rust bitcoin #1890 adds a method for counting the number of signature operations (sigops) in non-tapscript scripts. The number of sigops is limited per block and Bitcoin Core’s transaction selection code for mining treats transactions with a high ratio of sigops per size (weight) as if they were larger transactions, effectively lowering their feerate. That means it can be important for transaction creators to use something like this new method to check the number of sigops they are using.