By Antoine Poinsot
Source: https://delvingbitcoin.org/t/great-consensus-cleanup-revival/710
Lately I’ve been reviewing Matt Corallo’s “ consensus cleanup ” proposal. My interest is in figuring out:
- How severe the bugs are that the proposal is intended to fix;
- How much the proposed fix improves the worst-case scenario;
- With five more years of experience, can we do better? (Translator's note: Matt's proposal was made in 2019.)
- Is there anything else worth addressing?
Long story short : I think those bugs are bad. The worst-case block validation times are concerning. I also think that fixing the time warp bug is much more important than people often give it credit for. Finally, I think we can include a fix to avoid BIP30 validation after block 198 3702, and an additional limit on the size of legacy transactions that would provide a useful safety margin for block validation times.
I hope this post will stimulate discussion about the protocol bugs that the consensus cleanup proposal is intended to address. I hope to receive comments and feedback on each of the proposed mitigations, as well as potential suggestions for additional fixes. The section on block validation times is heavily abridged: I will share some numbers publicly, but the details of the strategy for producing destructive blocks will only be shared with long-time Bitcoin Core contributors and a small number of Bitcoin protocol developers.
Time Warp Vulnerability
The time warp vulnerability exploits the fact that difficulty adjustment periods do not overlap. Miners can use this to artificially lower the difficulty by moving the timestamp of the last block of a target adjustment period as far forward as possible (that is, 2 hours from now) and moving the timestamps of all other blocks as far back as possible. This stackexchange answer has a more detailed explanation.
How bad is it?
It is interesting to consider how this makes the situation worse, and what exactly it brings. After all, miners can always hold down the timestamp and not let it advance, even without exploiting the time warp vulnerability. But if the first block of a difficulty adjustment period is not timestamped earlier than the last block of the previous period, exploiting the difficulty adjustment mechanism will inevitably increase the mining difficulty. Conversely, by setting the first block of a period to a timestamp earlier than the last block of the previous period, the attacker can further reduce the difficulty while exploiting the low difficulty (the result of this game).
In practice, an attacker could fatally damage the network in just over a month from the start of such an attack. Starting at time t
, epoch N
, by the end of epoch N+1
, the attacker has already reduced the difficulty by half. This in turn allows them to mine all the blocks of epoch N+2
in a week, further reducing the difficulty by a factor of 2.5, and so on. In less than 40 days, the attacker can reduce the difficulty to 1, and mine millions of blocks at once. In addition to taking away all remaining block subsidies, this would destroy the security of all L2 protocols that rely on timelocks, and worsen the DoS attack surface (e.g., combined with the expansion of the UTxO set).
MTP (Median Time Past) is ignored here, as it is at best a minor annoyance for the attacker. However, this raises the question: although such an attack requires control of a large portion of the mining hashrate, could a small hashrate try opportunistic strategies to exploit it? For example, by moving the timestamp of the last block of an adjustment period as far forward as possible, and moving the timestamps of all other blocks as far back as possible (within the limits allowed by the MTP rule). Technically, this would have no (significant) cost to the miner, and might give them (and other miners) slightly more block rewards (at the expense of future miners). It turns out that using such a strategy has negligible marginal benefits for any small mining hashrate, so we can reasonably expect that miners will not try to exploit the time warp vulnerability on a whim.
Should we fix it?
Some have argued that miners will not intentionally shoot themselves in the foot. In fact, it is not a good idea to expect them to kill the chain they are mining. Instead, they may reach an equilibrium where they simply increase the rate of blocks produced by X%. I leave it to the reader to judge the political implications of miners being able to increase the available block space without changing the consensus rules between nodes. But we will point out that if a miner's cartel could reduce the difficulty by even a small amount by exploiting the time warp bug, it could keep the network on the brink of collapse for a few weeks.
Another common claim is that this is not urgent because the attack is obvious and would take a long time. I am very skeptical of the argument that users need to coordinate and decide on the validity of a block at a certain height outside of the consensus rules they are in. Moreover, a month is not a long time to coordinate and change Bitcoin's consensus rules. And, as mentioned before, it is uncertain whether there will be broad consensus to do so. Users like lower fees, miners like more subsidies. Given the current distribution of control over mining power and the exponentially decreasing block subsidy, it is not unreasonable to think that a cartel could form to try to exploit the time warp vulnerability.
Finally, some people argue that it is not urgent because the attack requires the participation of most mining power. I think this is too easy. The reason is that the time warp vulnerability greatly increases the damage that a 51% attack can cause. Originally, a 51% attack "only" temporarily censored transactions. But with a time warp attack, the entire network can be destroyed.
Can we come up with a better fix?
Probably not. The proposed fix is straightforward: make difficulty adjustment periods overlap. Matt's proposed change is the simplest and most obvious: constrain the timestamp of the first block of the current period by the timestamp of the last block of the previous period.
Worst case block verification time
It is well known that maliciously crafted non-segwit transactions can be extremely difficult to verify. Longer block verification times can give miner attackers an unfair advantage, hinder the propagation of blocks in the network (and their consistency), and even have harmful consequences for software that relies on block availability. To this end, the consensus cleanup proposal adds several additional restrictions on the use of traditional scripts.
How bad is it?
Very bad. In the worst case, I can come up with a block that takes 3 minutes to verify on my latest laptop's 16-core CPU; on a Raspberry Pi 4, it takes 1.5 hours. For obvious reasons, I have omitted the details of such a block here, as well as various methods for creating similarly difficult-to-verify blocks. I will share it with other protocol developers in a semi-private attachment post using Delving's private workshop feature. If you think you should know and I forgot to add you, please contact me.
How much of an improvement does the proposal provide over the worst-case scenario? Can we come up with more effective mitigation measures?
The mitigation proposed by the consensus cleanup proposal would invalidate the blocks I produced. Under the new limits, the worst block validates in 5 seconds on my laptop. I think we can go further and introduce limits on the size of traditional transactions to be safe.
Regarding the proposed mitigation, there are also concerns about "confiscation" (previously valid scripts becoming unspendable). I think these concerns are reasonable and can be addressed by only applying the new rules to scripts created after a certain block height.
Merkle tree attack using 64 byte transactions
Due to how the Merkle root is calculated in Bitcoin blocks, there are two (known) remaining attacks. Both involve concatenating two 32-byte hashes, which must be able to be successfully deserialized into a Bitcoin transaction. The (probably most famous) one is to trick a light node into accepting a transaction that is not confirmed by a block: have a 64-byte transaction confirmed by a block (and thus committed by the Merkle tree), but the last 32 bytes correspond to the txid of a transaction that was paid to the victim but was not confirmed by a block. The other is to trick a node into permanently banning a valid block: find a row of tree nodes that can all be deserialized into (invalid) 64-byte transactions. See this article by Suhas Daftuar for more details.
The consensus cleanup proposal treats transactions with a size of 64 bytes or less as invalid transactions, which can fix both problems at the same time.
How bad is it?
An attack against a light node (or anything accepting Merkle proofs, like sidechains) requires a brute force search in the 61 to (roughly) 75 bit range, depending on the amount of Bitcoin dedicated to the attack. This is expensive, and there are simple mitigations. For example, checking the depth of the Merkle tree by requesting a Merkle proof for the coinbase transaction will tell you how many transactions the block contains.
That is, this attack is estimated to cost $1 million , when "the latest Bitcoin mining ASIC computing power reaches 14TH/s". Now, it seems that the computing power of ASICs has risen to 400TH/s. In addition, this attack can forge any number of confirmations for a transaction. The cost is just to mine a fake block to deceive an SPV client, which is now a little higher (80 bits).
Attacks that fool Bitcoin nodes have been mitigated in Bitcoin Core by not caching block checks without context ( CheckBlock()
). Creating valid transactions is not explicit: the first transaction must be a coinbase transaction, which requires a brute force search of 224 bits.
64-byte transactions are a core vulnerability in Bitcoin because of the way the Merkle root is calculated in blocks. While both (known) attacks that arise from it can be mitigated, it would be good to avoid this risk of accidental firing while caching context-free block checks in Bitcoin Core.
Can we come up with a better fix?
64 bytes are not "safe" because 64 bytes is not enough to fit an output with a locking script (not spendable by anyone, and not locked forever) in a transaction. They have no known use, and have been treated as non-standard transactions by the network for 5 years. Given the vulnerabilities they introduce and their uselessness, it is reasonable to declare them invalid transactions.
However, this BIP proposes to invalidate transactions that are smaller than 64 bytes. Although they are useless (or not very useful), such transactions are harmless. I have always believed that a transaction type is not useless enough for us to invalidate them through a soft fork.
AJ also invalidated (exactly) 64-byte long transactions in his PR to Bitcoin-inquisition .
Wishlist
BIP30 Verification
BIP34 temporarily avoids running the relatively expensive BIP30 check on every block link. Starting from block height 198 3702, it is no longer possible to rely solely on BIP34. If a soft fork is to be proposed to fix a long-standing protocol bug, it would be best to make every coinbase transaction absolutely unique from now on.
A simple solution would be to have nLockTime
of the coinbase transaction set to the block height in which it was created. However, there is a more roundabout solution that might be easier for miners to deploy: make witness commitments mandatory in all coinbase transactions (from Greg Sanders). I haven't determined if there will be exceptions to this rule, but I would be very surprised if a pre-Segwit coinbase transaction with an output that happened to push a witness commitment header that started with 32 0x00
bytes.
Your favorite bug!
At this stage, I want to collect as many cleanup suggestions as possible, and make sure that if such a soft fork were to be put on the table, we have analyzed as carefully as possible all the fixes we can add.
Of course, suggestions should have reasonableness. For example, "ban ordinarys" is a boring proposal, and I doubt many people will participate. Moreover, let's focus on long-term, non-controversial bugs. For example, "a block taking longer than 30 minutes to verify means bad things", "broken Merkle tree calculations pose a fire risk", and "make coinbase transactions truly unique" seem completely non-controversial. On the other hand, while "let's lower the block size limit" may have reasonable reasons, it seems much more controversial to me.
For example, here are two things you can't convince me are worth proposing:
- Requires SegWit v0 transactions to also have the standard SIGHASH type byte.
- Limit the size of script public keys to reduce the growth of the UTXO set in the worst case.