On anyone-can-spend Pay-to-Taproot outputs before activation
Spending P2TR for fun and non-profit
Friday, July 23, 2021While working on taproot support for transactionfee.info, it became apparent that there already exist a few Pay-to-Taproot (P2TR) outputs on mainnet. Anyone can spend these outputs, but they are non-standard and thus not relayed between nodes in the Bitcoin peer-to-peer network. However, a mining pool can include non-standard transactions in their block. We cover the six P2TR outputs already present on mainnet and explain why the outputs can be spent by anyone before taproot activates. With the help of the f2pool.com mining pool, four P2TR outputs are donated to brink.dev, a non-profit company focused on supporting open-source Bitcoin development.
Taproot is a softfork upgrade to the Bitcoin protocol and tightens the consensus rules. A softfork forbids something that was previously allowed once it activates. Taproot restricts how native SegWit outputs, with a witness version of 1 and a 32-byte witness program, can be spent. The spending rules for other witness versions, nested SegWit, and native SegWit outputs with a witness version of 1, but longer or shorter witness programs are unaffected.
Existing P2TR outputs on Bitcoin mainnet
While it is possible to create P2TR outputs before taproot activates, it is not recommended to do so. Likewise, wallets shouldn’t generate P2TR addresses before activation. Nonetheless, at the time of writing, there are already six P2TR outputs on Bitcoin mainnet.
The first P2TR output was created on December 17, 2019, in a withdrawal
transaction from purse.io. Matthew Zipkin initiated a withdrawal
of 5431 sat to a witness version 1 bech32 address to test sending support for
witness version 1. He added his test results to the Bitcoin Optech
Compatibility Matrix and provided a screenshot showing the withdrawal on the
purse.io frontend. The public key encoded in the address is
0101010101010101010101010101010101010101010101010101010101010101
, which is
likely not generated from a private key. It is to be assumed that the private
key to this public key is unknown, and the funds won’t be spendable once taproot
activates.
The second P2TR output was created on January 28th, 2020. With a value of 700 sat, it is close to the default SegWit dust threshold of 294 sat. The creator of this output is unknown.
The third, fourth, and fifth P2TR outputs are test outputs created while checking send support to a witness v1 bech32 addresses that Pieter Wuille posted to the bitcoin-dev mailing list on October 19th, 2020. The third P2TR output has a value of 3656 sat and was created by Riccardo Casatta using the Blockstream Aqua wallet. The fourth P2TR output with a value of 50.000 sat was likely created by Mike Schmidt using the BRD wallet. It’s unknown who created the fifth P2TR output with a value of 100.000 sat.
The sixth P2TR output, with a value of 1324 sat, was created on July 7th, 2021. It is the only P2TR output created after taproot locked in on June 13th, 2021. The other P2TR outputs were created while it was still unclear when or if taproot would activate.
Why can P2TR outputs currently be spent by anyone?
Note (added on 2021-07-24): This post mentions anyone-can-spend outputs. While this term is commonly used to describe outputs with not yet enforced spending rules, it has been the source for a lot of misinformation about SegWit in the past 1. A better name might be “outputs with not yet consensus enforced spending rules” or “unenforced outputs before activation”.
Before taproot activates, these six P2TR outputs can be spent by anyone. However,
none of these P2TR outputs have been spent yet, as the spending transaction is
currently considered non-standard. Non-standard transactions aren’t relayed on
the Bitcoin network 2. Bitcoin Core checks each input for standardness in the
AreInputsStandard
function before accepting a transaction to the mempool. If
the spend UTXO is a P2TR output, the function currently returns false
,
indicating that the transaction has non-standard inputs. Nodes don’t accept the
transaction to their mempool and it is not relayed to peers.
However, a non-standard transaction can still be valid when directly included in
a block. Next to other checks, the transaction has to pass the script
verification. Standardness is not checked. In Bitcoin Core, the VerifyScript
function is responsible for script verification. The script verification for
native SegWit spends consists of two parts: the script evaluation and the
verification of the witness program.
During script evaluation, the scriptSig
is evaluated first. The resulting
stack is used as the initial stack state when evaluating the scriptPubKey
from
the UTXO referenced in the input. The script evaluation succeeds if it finishes
without failing, the stack is not empty, and the top stack element casts to
true
(is not zero). When spending native SegWit outputs like, for example, P2TR
outputs, the scriptSig
is empty. The scriptPubKey
contains the witness
version and the witness program. As the scriptSig
is empty, an empty stack is
used for the scriptPubKey
evaluation. There, the witness version and witness
program are pushed onto the stack. The script evaluation finishes. As the stack
isn’t empty and the top stack element is the witness program (which usually
isn’t zero), the script evaluation will succeed. This behavior makes SegWit a
softfork. SegWit transactions are valid for nodes without SegWit support as the
top stack element is not empty.
A keypath P2TR spend that will be valid and standard once taproot activates. A anyone-can-spend P2TR spend will likely have an empty witness, but otherwise look the same.
As a next step, the witness program is verified if the witness version is known.
If the witness version is unknown, the witness program is treated as valid 3.
One of the first checks during verification of version 1 witness programs (i.e.
when spending P2TR outputs) is if the SCRIPT_VERIFY_TAPROOT
script verification
flag is set. If unset, the verification succeeds before checking the witness
program. This flag is only set when taproot is active. This causes
taproot outputs to be anyone-can-spend before activation. The witness program
isn’t verified, and the witness can be left empty.
Spending P2TR outputs before activation
We demonstrate the spending of P2TR outputs before the taproot softfork activates by constructing a non-standard transaction that is consensus valid. The mining pool f2pool.com helps by including the non-standard transaction in a block.
For our transaction, we pick the first, third, fourth, and fifth P2TR output out of the six available outputs discussed earlier. The first output with a value of 5.431 sat will be unspendable upon taproot activation and would otherwise remain in the UTXO-set forever. The third (3.656 sat), fourth (50.000 sat), and fifth (100.000 sat) P2TR output were sent in test transactions with the knowledge that the funds will most likely be lost or donated to charity. This allows us to spend a total of 159.087 sat. We leave the other two P2TR outputs (700 sat and 1.324 sat) for someone else to spend either before or after activation.
Our transaction contains two outputs. The first output donates the full input amount of 159.087 sat (about 50 USD at the time of writing) to brink.dev to support open-source Bitcoin development. The transaction purposefully doesn’t pay a miner fee to maximize the donation amount. The second output is an OP_RETURN output with a link to this blog post. This makes it possible for someone finding the anyone-can-spend transaction to learn more about why the P2TR outputs were spendable before Taproot activation.
We constructed the transaction with a quick and dirty Rust script. For Bitcoin Core to accept the non-standard transaction, this patch had to be applied to v0.21.1.
The transaction b10c007c60e14f9d087e0291d4d0c7869697c6681d979c6639dbd960792b4d41
was included in block
0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad
(height 692261) mined by f2pool.com.
Show decoded transaction
Show raw transaction
Note (added on 2021-07-24): There is a downside to including a transaction spending P2TR outputs in a block before the taproot softfork activates. A few months or years after the softfork has activated, the activation height becomes fact and can be hardcoded into Bitcoin Core 4. If there would have been no spends from P2TR outputs on-chain before activation, the taproot activation height would have been irrelevant. The taproot rules could have been enforced starting with the Genesis block (or maybe starting at the SegWit activation). However, with the P2TR outputs spending transaction included in a block, the activation height needs to be kept as part of the consensus logic. This slightly increases the software complexity of Bitcoin nodes.
Changes on taproot activation
When taproot activates on block 709632, Bitcoin Core v0.21.1 and newer will start enforcing the taproot rules. Spending P2TR will only be possible by supplying a valid signature for the keypath spend or a by satisfying the script requirements for a scriptpath spend. However, older nodes that don’t know about the taproot softfork will continue to treat the P2TR spends as anyone-can-spend. This can become a problem if, for example, a mining pool forgets to upgrade and includes a transaction spending from a P2TR output without satisfying the taproot rules enforced by the network. The chain would split between upgraded nodes enforcing taproot and not upgraded nodes. It is recommended to upgrade production and payment handling nodes before taproot activates.
I like to thank f2pool.com for their cooperation. Without them including the non-standard transaction in a block, donating the P2TR outputs to brink.dev, wouldn’t have been possible. You can support me and my work here.
Some SegWit opponents claimed that the SegWit softfork could be reversed after activation and the outputs would then be anyone-can-spend. To learn more about this I recommend reading The Blocksize War – Chapter 5 – SegWit. ↩︎
A good summary on non-standard transactions and forward compatibility can be found in this comment by nullc on Hacker News. ↩︎
This allows introducing of new rules to currently unused witness versions via a future softforks. The witness program verification succeeds at nodes unaware of the softfork. ↩︎
See, for example, the notes from the Bitcoin Core PR Review Club on #19438: Introduce deploymentstatus for more information. ↩︎