/ home / newsletters /
Bitcoin Optech Newsletter #116
This week’s newsletter describes a proposed soft fork to enable a new type of fee bumping and summarizes research into scripts that can never be spent because they require satisfying both timelocks and heightlocks. Also included are our regular sections with summaries of updates to services and client software, a list of new releases and release candidates, and changes to popular Bitcoin infrastructure software.
None this week.
● Transaction fee sponsorship: Jeremy Rubin posted a proposal to the Bitcoin-Dev mailing list for a soft fork to add a new fee bumping mechanism that could be less vulnerable to abuse than the current Replace-by-Fee (RBF) and Child-Pays-For-Parent (CPFP) methods. Transacting pinning and other abuses against the existing system can be used to attack contract protocols. These problems have led to partial solutions such as anchor outputs that work with specific protocols (e.g. two-party LN channels) but aren’t easy to generalize and so are somewhat unsatisfactory.
At the consensus layer, Rubin proposes allowing transactions to optionally contain a special final output that commits to the txids of one or more other unconfirmed transactions. The transaction with the special output, called a sponsor transaction, may only be included in a valid block if every one of the transactions it sponsored is also included in that same block. This means a miner who wants the high feerate from a sponsor transaction will be incentivized to confirm low-feerate sponsored transactions. Beyond their special sponsorship output, sponsor transactions are normal Bitcoin transactions.
For the rules that control mempool acceptance and transaction relay (the policy layer), Rubin suggests a set of simple changes that allow anyone to sponsor any transaction currently in a mempool or to replace an existing sponsor transaction with a higher feerate alternative that makes the same commitment. The goal is to ensure that, as long as a sponsor transaction follows the rules and pays a high enough feerate, it will propagate across the network without running afoul of pinning or other attacks.
Rubin’s proposal comes with a reference implementation and discussion of design tradeoffs and forward compatibility. As of this writing, comments on the list have shown appreciation for Rubin’s work but also describe two significant complications:
● Floating payments still pinnable: Antoine Riard notes that, even with a change to the proposal to allow sponsoring particular inputs, a malicious counterparty can pin a particular input signed with
SIGHASH_SINGLE(e.g. HTLCs in the latest LN protocol or state transactions in eltoo) by including that input in a maximum size transaction.
● Breaks reorg safety guarantee: Suhas Daftuar reminds readers of a founding principle of Bitcoin’s design. As Satoshi Nakamoto wrote, “In the event of a block chain reorg […], transactions need to be able to get into the chain in a later block.” This principle is broken by sponsor transactions which are only valid in the same block as the transactions they sponsor.
The proposal was still being actively discussed just hours before publication of this newsletter. We’ll summarize any new notable discussion in future editions.
● Research into conflicts between timelocks and heightlocks: A post to the Blockstream engineering blog describes an interaction between different types of Bitcoin time locks (timelocks) and block-height locks (heightlocks). All transactions since Bitcoin’s initial release have had an
nLockTimefield. A soft fork activating at block 31,000 (December 2009) began comparing this field against a block header’s explicit time field and its implicit height (number of blocks since the Genesis Block). A block is only valid if every one of its transactions follows these two rules:1
If a transaction’s nLockTime is below 500 million, it must also be below the block’s height.
If a transaction’s nLockTime is equal to or above 500 million, it must be below the block header’s time (in epoch time).
This overloading of the single nLockTime field for two different purposes is efficient but has the obvious implication that a transaction can only use either a heightlock or timelock—not both.
Years later, the BIP65 soft fork activated in December 2015 added the
OP_CHECKLOCKTIMEVERIFY(CLTV) opcode that compares its argument against its spending transaction’s nLockTime field in the same way the nLockTime field is compared to the containing block’s height or time field. This allows scripts to prevent money received to them from being spent until after a certain future height or time. However, the Blockstream post explains that this also has the non-obvious implication that it’s possible to create a script that’s unspendable because it requires the simultaneous use of both heightlocks and timelocks. For example, a payment to the following script can never be spent:
1 OP_CLTV OP_DROP 500000001 OP_CLTV
The first condition allows the spending transaction to be included in block 1 or later, so any block after early January 2009, and the second condition allows it to be included in any block after early November 1985. Both conditions are true today—but they can’t both be satisfied using a transaction’s single nLockTime field. The post notes that the same problem can apply when a transaction has multiple inputs each with their own script. For example:
Input 0: 1 OP_CLTV Input 1: 500000001 OP_CLTV
The problem also applies to relative timelocks and relative heightlocks created using BIP68 sequence numbers and the BIP112
The post notes that the Miniscript compiler has been updated to deal with the possible conflicts as best as possible. It will identify when one or more of the ways to satisfy a script contains conflicting locks and will return a warning. Because of the conflict, it’ll also not be able to provide a full analysis of the script. Additionally, the compiler for the policy language will now deliberately fail on policies that mix timelocks and heightlocks, e.g.
thresh(3,after(1),after(500000001),pk(A)). Note: as of this writing, this change is only a pending PR to the Rust version of the miniscript library and has not yet propagated to the online live demos for miniscript or minsc.
Changes to services and client software
In this monthly feature, we highlight interesting updates to Bitcoin wallets and services.
● Swan supports sending to bech32 addresses: Swan, through their custodian Prime Trust, now supports withdrawals to bech32 addresses.
● Ledger Live adds manual coin selection support: Moving from a first-in, first-out UTXO selection model, Ledger Live now also supports manual coin selection for either privacy or fee-minimization benefits.
● Sparrow wallet announced: Sparrow wallet is a new desktop wallet supporting single or multisignature addresses, PSBT, hardware wallets, and coin selection.
● JoinMarket 0.7.0 adds BIP78, PSBT: JoinMarket 0.7.0 includes support for BIP78 payjoin for payments. PSBT support was also added in order to facilitate the implementation.
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.
- ● LND 0.11.1-beta.rc4 is the release candidate for a minor version. Its release notes summarize its changes as, “a number of reliability improvements, some macaroon [authentication token] upgrades, and a change to make our version of anchor commitments spec compliant.”
Notable code and documentation changes
Notable changes this week in Bitcoin Core, C-Lightning, Eclair, LND, Rust-Lightning, libsecp256k1, Hardware Wallet Interface (HWI), Bitcoin Improvement Proposals (BIPs), and Lightning BOLTs.
● Bitcoin Core #16378 adds a new
sendRPC to the wallet. This new RPC is designed for maximum flexibility and includes options such as multiple outputs (allowing payment batching), coin selection, manual or automatic feerates, and PSBT format. It is intended to unify the functionality of the
sendmanyRPCs, which may be deprecated in a future release. For the full list of options, see the RPC help text.
● Bitcoin Core #19643 adds a new
-netinfooption to the
bitcoin-clicommand to display a peer connection dashboard. This dashboard offers node operators a bird’s-eye view of peer connection details such as directionality, relay type, network family, and uptime. An optional argument from
4may be passed to display various levels of detail.
$ watch -n 0.1 ./src/bitcoin-cli -netinfo 3 Bitcoin Core v0.20.99.0-bf1f913c44 - 70016/Satoshi:0.20.99/ Peer connections sorted by direction and min ping <-> relay net mping ping send recv txn blk uptime asmap id version in full onion 1 1 0 10206 70015/Satoshi:0.20.1/ in full ipv6 246 246 1 9 0 1 16509 10202 70015/Satoshi:0.19.1/ in block onion 37686 425955 42 42 25 10143 70015/Satoshi:0.20.1/ [...] out full ipv4 94 198 3 1 0 229 956 12998 7809 70015/Satoshi:0.19.0.1/ out block ipv6 107 269 64 64 949 5577 7835 70015/Satoshi:0.16.0/ out full onion 440 1180 4 4 0 257 9574 70015/Satoshi:0.18.1/ ms ms sec sec min min min ipv4 ipv6 onion total block-relay in 0 17 8 25 2 out 8 2 8 18 2 total 8 19 16 43 4 Local addresses [redacted] port 8333 score 6401 [redacted].onion port 8333 score 1085
● Bitcoin Core #15454 no longer creates a new wallet when the program is started for the first time. Instead, the user is prompted to either load an existing wallet or create a new named wallet. Wallets created by default in earlier versions of the software will still be loaded by default, and newly created wallets can still be added to the load-on-start list (see Newsletter #111). By removing the default wallet creation, users gain more exposure to the options for customizing their wallet options, such as enabling wallet encryption, creating a watch-only wallet, or creating a wallet that’s ready to import output script descriptors (e.g. for multisig).
● Bitcoin Core #19940 updates the
testmempoolacceptRPC with additional result fields for the transaction’s vsize and total transaction fee if the transaction can be added to the mempool. In particular, the fee is information that some users need, which is guaranteed to be available for a mempool transaction, and which cannot be trustlessly obtained before broadcasting a non-wallet transaction unless several other RPCs are run in sequence (e.g. using
● LND #4440 records the number of times the local node sees a peer going offline and then coming back online, known as flapping. The node will limit the number of event records it’ll store about peers who frequently flap to avoid filling its database with too much noise. The
listchannelsRPC is also updated to display each peer’s flap rate.
● LND #4567 adds a new
--maxchansizeconfiguration parameter that allows setting the maximum amount of money that can be contained in a new channel. Now that LND supports large channels (see Newsletter #107), this setting allows users to set a limit on the maximum amount of money they could potentially lose in a single channel if something goes wrong.
● LND #4606 and #4592 improves LND’s effectiveness at fee bumping anchor outputs. The first PR calculates the feerate needed to confirm both the child anchor transaction and its parent commitment transaction. The second PR enables automatic fee bumping when a commitment transaction needs to be confirmed within the next several blocks.
Timelocks and heightlocks based on a transaction’s nLockTime are a bit more complicated than described here due to an interaction with a transaction’s one or more nSequence fields. If all nSequence fields are set to their maximum value (
0xffffffff), then the transaction can be included in any block. For details about the possible motivation for the interaction between nLockTime and nSequence (and signature hash flags), see an email with quotes attributed to Satoshi Nakamoto.
Additionally, the BIP113 soft fork activated in July 2016 means nodes now compare timelock values to a block’s computed Median Time Past (MTP) rather than its explicit header time. ↩