Contentious Hard Forks and Nakamoto Consensus, Part 2
This is a two-piece, Part 1 of which explains why Nakamoto Consensus is currently not applicable to most types of forks, and especially not contentious ones. It can be found here.
DISCLAIMER: This is an idea I’ve been thinking about for a few weeks. It is not yet a proper proposal, but I hope that with some debate and refinement it will end up as a proper BIP.
To reiterate the points from Part 1, these are the reasons Nakamoto Consensus is currently not applicable for Soft Forks, Hard Forks, and Chain Splits. I’m using the general definitions of Soft and Hard Forks as subsets and supersets of the prior ruleset respectively, although there are certainly edge cases that complicate this:
- In a Soft Fork, the old ruleset can Yield to the new, since new blocks are still compatible with the old ruleset
- In Hard Forks, the new ruleset can usually Yield to the old for the same reason
- In a Chain Split, neither ruleset can Yield because they are mutually incompatible
The deciding factor here is obviously if one ruleset is compatible with the other or not. If we could find a solution where one ruleset could recognize the work of another and yield its hashrate to it, then we would have basically solved the problem for all these situations.
BIP135 is an attempt at using version bits to signal support for a proposal, requiring some threshold majority of the last 2016 blocks to support it for it to be activated. BIP135 is a more generalized and committing solution than the previous BIP9, but neither of these solve the problems that arise in a contentious hard fork, where one or both sides are unwilling to compromise. In the case of BIP135, this would default to no change, because the proposal is dependent on support from some majority of the hashrate to be activated in the first place. Furthermore, as with the recent BCH Chain Split, one side is currently able to seek a Chain Split while maintaining a claim of not wanting a split, by overstating their supporting hashrate, and running a social media campaign demonizing the other side as the one seeking the split. Additionally, a malicious actor can fake support for a proposal, then withdraw it as soon as activation is set.
What we can do instead is use the version bits to signal the configuration of some alternative ruleset during some predetermined period and allow the temporary fork with the most accumulated work decide which configuration to go forward with.
Using this framework, the normal procedures of a proposal will be followed up until the point where the various dev teams implement support for it. At this point, the following procedure should be followed:
- The proposal is designated a version bit for signaling
- A pseudo-activation point is set (presumably the normal hard fork height)
- A win condition for the hashing competition is agreed upon
- All implementations add optional or default support for the proposal
- Pseudo-activation height is reached: the chain splits
- Nakamoto Consensus decides the configuration with most hashrate support
- All implementations recognize NC-chosen configuration and yield
- Network settles on one configuration: proper activation
Instead of using version bits to signal support prior to activation like BIP135, this framework uses the version bits to communicate the intended ruleset during the activation period. This allows any implementation to keep track of all forks and validate their blocks according to the appropriate ruleset.
The win condition for the hashing competition is whatever set of rules decides the winning chain. This can be a pure “longest chain wins” rule where the first fork to become longer wins outright, a win condition where one chain must be X blocks longer than the other(s) to win, a “longest chain after X blocks” condition, etc. As long as the win condition is agreed upon prior to the activation period and makes it possible to determine a winner, any condition is valid.
The most complicated part of this framework is the necessity for every implementation to support every proposal. This approach is currently only supported by Bitcoin Unlimited, but BU choosing the approach shows that it’s well within the realm of possibility. A proposal should have some level of support before requiring every dev team to implement it, but where this threshold should be is something I believe the technical community should decide on in cooperation.
Prior to the activation period, some network action should be agreed upon that splits the chains between the different proposals. If we have a proposal for a new transaction format, the creators of the proposal should create a transaction using the new format prior to the activation period and include it as part of their proposal. This contentious transaction should be included in a block as soon as the activation period starts, to ensure a clean split between the chain that supports the proposal and the one that doesn’t. For the duration of the activation period, other contentious transactions that would have split the chain should be ignored; this is to ensure that operation for non-contentious usage stays as normal as possible. When the competition is over, those contentious transactions will either no longer be contentious, or they will be discarded as invalid.
As soon as the win condition is met, all implementations should recognize the configuration that met it, and reconfigure themselves to join the consensus. The contentious chain(s) will be discarded, and the network settles on one configuration. Whatever new proposals that are still valid are now considered fully activated, and can be utilized by normal users.
This framework should allow Nakamoto Consensus to decide any proposal, even with situations that are currently considered mutually incompatible chain splits. It is still completely possible to force a permanent chain split by simply not following the framework, but if this is implemented as standard procedure it should be impossible to force a permanent chain split while credibly claiming to not want to. The only downsides to this are the necessity for every dev team to implement support for every serious proposal, and a slight delay on the proper activation time of new functionality for normal users. BU already taking the approach of supporting everything shows that the approach is viable, what constitutes a “serious proposal” can be refined and standardized, and for most proposals the delay should be a few hours at most, which is negligible in every scenario except certain emergency situations.