Space shuttle cockpit instruments
photo of space shuttle cockpit instruments

hardfork_prototype_0 - an early prototype of a Bitcoin hard fork

Technical Details

This last part discusses aspects of the HFP0 code in more detail.

NOTE: This part is still under construction. Things may change.

Preamble

"It was a lot of fun digging into the code to figure out how to implement this fork."

- 'rocks' about satoshisbitcoin, in the Bitcoin Forum thread "Announcement - Bitcoin project to full fork to flexible blocksizes"

Before I delve into the HFP0 code, a word of thanks to rocks, who inspired me to start digging into the Bitcoin code, and the kind members at the Bitcoin Forum without whose patient explanations and words of encouragement I wouldn't have been able to get started on this journey. And what a fun journey it is!

Through it, I met a number of people who are all interested to see Bitcoin succeed, scale on-chain and fulfil the vision that Satoshi offered in the whitepaper. I'm honored to be a part of this growing Bitcoin community, together we can overcome present obstacles and bring Bitcoin to more people in this world.

Before starting on this prototype, I had never looked seriously at the Bitcoin source code. I compiled it a few times, as I usually do with most software which I want to run. Fortunately Bitcoin is free software, released under the MIT license, and no-one can really take that freedom away easily (thank you Satoshi!) As such, anyone can fork the code, at any time. It's not that difficult, so why's no-one forked Bitcoin to upgrade the block size?

The answer is: people have tried, by asking nicely. For several years. The most widely used implementation is now in the hands of developers who have decided that a block size upgrade is not part of their short-term roadmap, even though the network is running close to capacity. This is their right as maintainers of their implementation, but it's the right of people who disagree to produce the code changes they want to see and run them.

Branches in the hardfork_prototype_0 repository

The initial HFP0 code release will be placed into a separate 'snapshot' branch named 'hfp0_mXXXXXX_tYYYYYYY', where XXXXXX and YYYYYYY represent the mainnet and testnet trigger heights configured in the code.

When downloading with Git, make sure you don't select the 'develop' branch, as it only contains the historical Bitcoin code up to the commit where HFP0 development started (on March 7, 2016). Use the hfp0_m666666_t9999999 branch instead, e.g:

$ git clone -b hfp0_m666666_t9999999 https://github.com/BTCfork/hardfork_prototype_0.git hfp0_m666666_t9999999

hardfork_prototype_0 is intended to be a repository of code snapshots instead of an active development repo. Active development will take place elsewhere from now on.

I may yet add additional snapshot branches if I decide it is helpful to demonstrate something using this prototype. In particular, I am experimenting with signature changes for replay attack prevention and cleaner network separation.

GitHub issues and pull requests for this repo may be answered, but merges will not be done in hardfork_prototype_0 repo.

If someone provides a change, I will look at it, and if I deem it useful it might make it into some future snapshot.

If anyone wants to actively develop HFP0 further, please fork the snapshot you like and maintain it yourself.

Why a single huge commit?

This development was conducted privately while I was learning about the Bitcoin code, and the full commit history is long and messy. Up to the first code release there have been 317 commits since March 7, 2016. I still maintain several unclean experimental feature branches.

It would take large effort to straighten it out into a series of nice, atomic functional commits. I'm not even sure that's always entirely possible with this set of changes, at least not while keeping things compiling between certain commits.

Therefore, instead of trying to re-arrange the commit history, I have carefully marked modifications with tagged change markers that identify the functional area(s) to which a change is associated. This has been done where possible - for some files it is not possible as they permit no comments etc.

The marker tags should make it relatively easy to understand what a change is about and to focus on a set of changes of interest for review.

I agree with those who would have preferred a clean, public development with an easily understandable commit history. I'm sorry I couldn't provide that with this first prototype. My future work on improved spin-offs will be conducted using public repositories, and thus it should be easier to understand and review changes.

Why does it change so many files?

The short answer: because this is not a minimal fork.

  1. It includes some quite hefty external changes:

    • modified scrypt POW from satoshisbitcoin
    • BitPay's adaptive block size
    • MIDAS per-block difficulty retargeting algorithm
    • Xtreme Thinblocks from Bitcoin Unlimited
    • retrofit of active soft-fork BIPs 65,68,112,113
    • test framework updates from Classic v1.1.0

    A minimum viable fork (MVF) up to 2MB which does not change the POW would likely be based on a newer client version of Core/XT/Classic/BU which already has the BIPs and necessary test framework updates included. It would probably only need some difficulty algorithm adjustments from the list above.

  2. There are large amounts of HFP0 debug traces left in the provided code, which would likely be removed for a proper release.

I haven't worked out exactly how much is left if traces were to be removed, the new POW code discarded and only the minimal forking changes tallied.

It doesn't make much sense to tally that up for HFP0, because certain features are missing or not implemented to the required degree (e.g. network separation, replay attack protection) and the test coverage is incomplete.

However, it is obvious that a viable non-minimal spin-off client will have substantial code changes.

Meaning of the change markers

The following table briefly explains the meaning of the changer marker tags:

Tag Meaning
REN cosmetic renames (in docs, titles, output strings, GUI menus etc.)
FRK forking actions at triggering height
DIF difficulty algorithm update (MIDAS)
BSZ Adaptive block size algorithm based on BitPay implementation
SED DNS seeds and static IPs (emptied out / dummy values)
PER Peer handling during fork (rudimentary)
CLI Client version update
ALR Alert key disabling
POW fork to new POW code (overriden by config switch --disable-newpow)
XTB Xtreme Thinblocks implementation
DBG fork related debugging traces (removable)
CLN Cleanup related to removal of obsolete code
TST Additional tests (unit, system) or fixes to tests
CLT BIP65 OP_CHECKLOCKTIMEVERIFY
RLT BIP68 Relative Lock-time using consensus-enforced sequence number
CSV BIP112 CHECKSEQUENCEVERIFY
MTP BIP113 Median time-past as endpoint for lock-time calculations
TMP temporary settings for testing only
CRY Cherry-picked miscellaneous fixes from other clients which otherwise trouble testing

Overview of file changes

List of added files (w.r.t. Classic v0.12.0cl1)

File Comment
qa/rpc-tests/bip68-112-113-p2p.py BIP tests from recent upstream
qa/rpc-tests/bip68-sequence.py BIP tests from recent upstream
qa/rpc-tests/hardfork_bigblocks.py hardfork + big block test
qa/rpc-tests/hardfork_minebigblock.py hardfork + big block test
src/blocksizecalculator.cpp adaptive block size (BitPay), modified
src/blocksizecalculator.h adaptive block size (BitPay), modified
src/crypto/modified_scrypt_sha256.cpp modified scrypt (new POW)
src/crypto/modified_scrypt_sha256.h modified scrypt (new POW)
src/crypto/modified_scrypt_smix.cpp modified scrypt (new POW)
src/crypto/modified_scrypt_smix.h modified scrypt (new POW)
src/crypto/sysendian.h modified scrypt (new POW)
src/test/blocksizecalculator_tests.cpp C++ unit test for BSZ
src/test/thinblock_tests.cpp C++ unit tests for Xtreme Thinblocks
src/thinblock.cpp sources related to Xtreme Thinblocks
src/thinblock.h sources related to Xtreme Thinblocks
src/xthinblocks.cpp sources related to Xtreme Thinblocks
src/xthinblocks.h sources related to Xtreme Thinblocks

List of removed/replaced files

File Comment
qa/rpc-tests/bigblocks.py replaced by hardfork_bigblocks.py
qa/rpc-tests/forknotify.py removed as part of unknown-version block check removal

List of modified files

File Overview of significant changes
README.md updated to give overview of HFP0
configure.ac client rename and support for new --disable-newpow configuration parameter
contrib/gitian-descriptors/gitian-linux.yml change remote URL (dummy)
contrib/gitian-descriptors/gitian-osx-signer.yml diskimages permission fix from upstream
contrib/seeds/nodes_main.txt remove public seeds, add private seeds
contrib/seeds/nodes_test.txt remove public seeds, add private seeds
qa/pull-tester/rpc-tests.py add new tests, remove forknotify.py and rename bigblocks.py
qa/rpc-tests/maxuploadtarget.py updated as per BU0.12.1bu to use maxuploadtarget of 200MB
qa/rpc-tests/p2p-acceptblock.py set correct block version after fork
qa/rpc-tests/p2p-fullblocktest.py add reminder that this test might need updating for > 1MB blocks
qa/rpc-tests/pruning.py add scaleblocksizeoptions=0
qa/rpc-tests/sendheaders.py set correct block version after fork, add XTB changes
qa/rpc-tests/test_framework/blockstore.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/blocktools.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/comptool.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/mininode.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/netutil.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/script.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/socks5.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/test_framework.py merged test_framework update from Classic v1.1.0
qa/rpc-tests/test_framework/util.py merged test_framework update from Classic v1.1.0, read in fork height triggers from C files
src/base58.cpp fix backport (cleanse full vChTemp vector)
src/bitcoin-cli.cpp renaming only
src/bitcoind.cpp shutdown improvements for new POW (from satoshisbitcoin), renaming
src/bitcoin-tx.cpp renaming, added TODO about signature capability once replay attack protection is implemented
src/chainparams.cpp split powLimit into powLimitHistoric and powLimitResetAtFork, add nHFP0ActivateSizeForkHeight and MIDAS parameters, dummy DNS seed, removed Classic parameters
src/chainparamsseeds.h replaced public with private seeds (generated from contrib/seeds/nodes_*.txt)
src/clientversion.cpp renamings, make scrypt/sha256 variant visible in client name
src/consensus/consensus.h add conditionals (HFP0_POW, HFP0_DEBUG_* flags), new MAX_BLOCK_SIZE (2MB), add fork height constants and new POW limits for mainnet/testnet/regtestnet, add static variables for adaptive block size (BSZ), remove Classic constants
src/consensus/params.h factor some MIDAS parameters out into here, add powLimitHistoric and powLimitResetAtFork, remove Classic-related majority/expiration/grace period params and access functions, add nHFP0ActivateSizeForkHeight variable and access function
src/hash.cpp merge HashModifiedScrypt() from satoshisbitcoin
src/hash.h merge HashModifiedScrypt() from satoshisbitcoin
src/init.cpp disable alert system, add XTB debug=thin argument, add BSZ scaleblocksize argument, renamings, BSZ update in CreateNewBlock
src/main.cpp activate BSZ after fork trigger, XTB merges, BSZ initialize global variables, added lots of debug traces in CheckTransaction, BIP merges, replace MAX_STANDARD_TX_SIGOPS with BSZ dynamic maxStandardTxSigops variable, pass fork POW limit to CheckProofOfWork if fork blocks, replace Classic's DidBlockTriggerSizeFork() with DidBlockTriggerHFP0SizeFork(), replace nMaxLegacySigops by maxBlockSigops, ban peers which serve non-fork blocks after trigger height, merge Core PR#7919 bugfix, remove some obsolete Classic bits
src/main.h parameterize MaxBlockSize() and other functions with block height, add UpdateAdaptiveBlockSizeVars() to factor out BSZ updates. Some XTB, ALR, BIP changes.
src/Makefile.am add new files for POW, BSZ, XTB to compilation (see added files)
src/Makefile.test.include add new files for BSZ, XTB
src/merkleblock.cpp BSZ: replace MAX_BLOCK_SIZE constant with maxBlockSize
src/miner.cpp FRK, BSZ and POW-related changes
src/miner.h some shutdown-related improvements from satoshisbitcoin
src/net.cpp Mostly XTB, use BSZ dynamic size instead of MAX_BLOCK_SIZE
src/net.h XTB merge
src/policy/policy.cpp merge 4fea8e741ba38b2c1c4fb1c79962234f711c846e (use MAX_STANDARD_VERSION for tx version check)
src/policy/policy.h bump DEFAULT_MAX_BLOCK_SIZE to 1MB, BSZ: add DEFAULT_SCALE_BLOCK_SIZE_OPTIONS, BIPs: add STANDARD_LOCKTIME_VERIFY_FLAGS
src/pow.cpp add MIDAS
src/pow.h add MIDAS
src/primitives/block.cpp POW: add cache of past modified scrypt hashes
src/primitives/block.h add FULL_FORK_VERSION_* constants, removed Classic DEFAULT_2MB_VOTE
src/primitives/transaction.cpp BIP68 merge
src/primitives/transaction.h BIP68 and 4fea8e741ba38b2c1c4fb1c79962234f711c846e merge
src/protocol.cpp XTB merge
src/protocol.h XTB merge
src/qt/askpassphrasedialog.cpp renaming only
src/qt/bitcoin.cpp renaming only
src/qt/bitcoingui.cpp renaming only
src/qt/bitcoinstrings.cpp renaming only
src/qt/guiutil.cpp XTB add XTHIN to services
src/qt/intro.cpp renaming only
src/qt/rpcconsole.cpp renaming only
src/qt/splashscreen.cpp renaming only
src/qt/splashscreen.h renaming only
src/qt/utilitydialog.cpp renaming only
src/rpcblockchain.cpp only TODOs for more HF descriptive info
src/rpcmining.cpp FRK, DIF, BSZ changes
src/rpcnet.cpp renamings, XTB thinblockstats added
src/script/interpreter.cpp BIP112 merge
src/script/interpreter.h BIP112 merge
src/script/script_error.h BIP112 merge
src/script/script.h BIP112 merge
src/sync.cpp XTB, Classic bugfix backport (disabled onlyMaybeDeadlock assert due to too many false positives)
src/test/alert_tests.cpp only harmonize unit test name with filename
src/test/block_size_tests.cpp block size tests (incl. around fork height)
src/test/checkblock_tests.cpp only harmonize unit test name with filename
src/test/data/tx_invalid.json BIP112 merge
src/test/data/tx_valid.json BIP112 merge
src/test/miner_tests.cpp complex inherited BIP68 test changes. File marked as changed by BIP68, individual changes not marked separately.
src/test/prevector_tests.cpp only harmonize unit test name with filename
src/test/script_tests.cpp BIP68 merge
src/test/test_bitcoin.cpp reset BSZ global vars between tests, BIP112 merge
src/test/test_bitcoin.h BIP112 merge
src/test/transaction_tests.cpp BIP112 merge
src/test/txvalidationcache_tests.cpp only harmonize unit test name with filename
src/timedata.cpp renaming only
src/txdb.cpp DIF: use appropriate POW limit
src/txdb.h XTB merge
src/txmempool.cpp BIP68, BIP112 merge
src/txmempool.h BIP112 merge
src/univalue/include/univalue.h XTB merge
src/version.h split PROTOCOL_VERSION into POW_PROTOCOL_VERSION and SHA_PROTOCOL_VERSION

List of modified files without recognizable change markers

The following is a list of files which didn't permit adding formal change markers.

File Comment
contrib/gitian-descriptors/gitian-linux.yml YAML data, change is simply a deflected URL
src/test/data/tx_invalid.json JSON data, merge from CSV BIP
src/test/data/tx_valid.json JSON data, merge from CVS BIP
contrib/seeds/nodes_main.txt list of addresses processed by another script
contrib/seeds/nodes_test.txt list of addresses processed by another script

There are also some Python files in qa/rpc-tests/test_framework which have been updated based on the Classic v1.1.0 code. In these files, not every Classic-related change is marked - the files are marked generally with a single-line TST marker comment underneath the file header:

# HFP0 TST: merged test_framework update from Classic v1.1.0

Building

Build instructions for Classic 0.12.0 should work fine. Platforms I've compiled and tested on:

  • Debian 7 (x86_64 and i686), gcc 4.7.2

  • Debian 8 (x86_64), gcc 4.9.2

HFP0 adds a new configuration option: --disable-newpow .

Unless you specify this option, the client is built to switch to the new POW at the trigger height.

If you specify --disable-newpow, the fork keeps using Bitcoin's existing SHA256 after it triggers.

Test Status

What follows is a brief overview - I might update this with more detail later on.

I have tested this prototype only in an isolated test environment (using up to 4 VMs). Most of my testing was done using regtestnet, the regression test chain. It has NOT been tested on the real testnet or on mainnet.

The C++ unit tests (src/test/test_bitcoin) should all pass. You will see a message on standard output:

CreateAndProcessBlock: ProcessNewBlock, block not accepted

I added this message as a troubleshooting aid to see when a block was not accepted. It does not signify a test failure, and can be ignored.

Regression/integration tests can be run with qa/pull-tester/rpc-tests.py .

The tests bip68-sequence.py and pruning.py currently fail. For bip68-sequence, it is presumed to be a policy code issue that has been fixed in later versions of other clients (a similar issue was present on Classic 0.12 builds, but has been fixed in Classic 1.1). I have not identified the exact change that could fix it, but the test failure is likely unrelated to changes made by HFP0.

The pruning test failure might be due to a presumed bug in how the fork handles re-orgs across its trigger, but it could also be something else.

Rudimentary hardfork / bigger block QA tests are implemented, but they are lacking in some test cases (re-orgs across the fork trigger height, and fine-grained testing around the trigger height). They also specify a soft block limit of 2MB, and don't exercise the theoretical maximum of even that soft limit. A more complete test should try to test up to MAX_BLOCK_SIZE without a soft block limit. This involves a substantial overhaul of the big block tests.

Adaptive block size tests are limited to the blocksizecalculator_tests suite, and would need to be extended with more test cases and integration tests.

There are no unit tests / regression tests for MIDAS yet.

I welcome any feedback from others who are able try out this prototype in their own test environments or on the actual testnet.

Further development

I will not develop this HFP0 prototype further to production readiness.

I consider it more important that Minimum Viable Forks are produced, with solid test coverage and requirements input from the wider community.

The BTCfork community (links below) is doing just that, working with users, developers and businesses in the Bitcoin space to develop improved forks, starting from MVFs and later hopefully supporting the development of fuller-featured fork candidates. I shall be working with them to bring viable forks to maturity.

If you want to get involved, you are welcome to get in touch on any of the channels below.


Feedback on the code

If you wish to provide feedback on the code, feel free to use GitHub's comment features or raise issues.

I won't fix issues directly in the hardfork_prototype_0 repository, but I may include fixes in future code snapshot, if any take place on this repo, and I'll try to respond to any sensible comments there.

Alternatively, I've opened a Reddit thread in /r/btcfork to gather comments and questions.

Posted Wed 21 Sep 2016 10:00:00 CEST Tags:
Farmers carrying hay on pitchforks
photo of farmers carrying hay on pitchforks

hardfork_prototype_0 - an early prototype of a Bitcoin hard fork

Part 2 - Technical overview

In this part, I will give a high-level view of the prototype's design, some rationale for choices I made during its development, and an account of what I think is missing, unfinished or not well-implemented compared to how I now imagine a good, safe spin-off.

HFP0 in brief

  • Hard fork triggered purely on block height (separate trigger heights for mainnet/testnet/regtest)
  • Proof-of-work: SHA256 or satoshisbitcoin's modified scrypt, depending on build configuration option
  • Difficulty reset to low value at fork trigger
  • Difficulty algorithm after fork height: MIDAS (per-block retargeting, similar to Dash)
  • Block size cap: adaptive (BitPay) with floor of 2MB and ceiling of 4MB
  • Block propagation: Xtreme Thinblocks (from Bitcoin Unlimited)
  • Alert system disabled
  • RBF: disabled (courtesy of Classic 0.12 baseline)
  • Network separation: DoS score banning (no change of network magic or port numbers)
  • Retrofitted: BIP9, BIP65, BIP68, BIP112, BIP113 + minor cherry-picked bugfixes from various clients

A reminder: HFP0 is a prototype, not ready for production use

You are welcome to test and play with hardfork_prototype_0, but I strongly suggest you don't put any money (yours or anyone else's) at risk doing so. It's a prototype spin-off which not ready for production. As with any other fork code (or altcoin), you should run it safely.

Feel free to use whatever of it appears useful to your own development, and if you have criticism and feedback, leave comments on /r/btcfork, on the Bitcoin Forum or on any channel of the BTCfork community.

You don't have to be mad to attempt a SHA256 spin-off, but...

Cryptocurrency is a bit of a war zone, with new currencies arising and coming under attack constantly. It's very much survival of the fittest, and one of Bitcoin's advantages has been its substantial network effect that stems from being the first cryptocurrency to 'make it big'. Bitcoin is a gateway to acquiring amounts of other cryptocurrencies and still occupies pole position in the cryptocurrency competition. It has a sizeable established network and surrounding ecosystem which act as an immune system.

Unlike some altcoins which purposefully choose their own unique POW, HFP0 started out under the premise that it would not change the traditional Bitcoin SHA256 POW, specifically to enable existing miners to support it, as the strong security of Bitcoin rests on their hashpower.

A spin-off of Bitcoin which retains the POW and ledger must compete head-to-head with the existing network on its technical value proposition. This could well trigger that immune system to fight against the spin-off using a portion of its substantial hashpower and financial reserves instead of letting the market decide on more technical merits.

HFP0 was designed to survive in an environment where it would be attacked by the existing miners. Such attacks are not hypothetical - at least one existing Bitcoin Core developer has a track record of attacking other cryptocurrencies. Angel investor Chandler Guo, who backs Chinese Bitcoin enterprises, including mining-related companies, has previously expressed intention to use hashpower at his disposal to perform a 51% attack on another cryptocurrency's fork he didn't like. Therefore it is reasonable to assume that some Bitcoin miners might defend their interests with such means.

Is it possible to defend such a spin-off against these overwhelming odds? Provided that you have a well-validated client (not a prototype) and can get some pools, exchanges and miners on board from the start, I'm confident it could work. It would nevertheless require additional defensive measures which satoshisbitcoin didn't need because

  1. it changed the POW to something ASIC-resistant
  2. it only increased the block size very conservatively, to 2MB

Before going over the list of HFP0 additions / changes in more detail, a word on the mainnet / testnet block height triggers you will find in the code (SIZE_FORK_HEIGHT_*). They have been intentionally set to dummy figures. The regtest trigger height is set to 1000 to prevent other tests (related to BIP9-counted softforks) from interfering with the hardfork-specific tests. I wouldn't recommend lowering that value below 1000 (initially I had set it to 160 but after merging BIP9 and other BIPs I quickly found out that it was easier just to raise it than get other range-dependent tests to play nicely with the fork).

On to the other requirements that have been implemented:

1. More reactive difficulty retargeting

A block height fork needs to reset the difficulty to a low value when it triggers, so that miners can mine successfully and roughly meet the 10 minute average confirmation times to which users are accustomed. In the initial stages, the aggregate hashrate of the fork chain can be expected to be low compared to the incumbent chain, and relatively speaking, much more variable.

In this situation, there are a number of majority attacks that can be executed by miners of the existing chain.

Hash bombing is an attack that can be used against multiple "naive" forks if they don't adjust their difficulty quickly enough.

The attacking miners temporarily ramp up the difficulty on one fork, then move on to the next, leaving the previous fork chain to languish while its lesser-powered miners are unable to find blocks quick enough at the now high difficulty ... rinse and repeat.

To fend off such attacks, spin-offs need to be able to adjust their difficulty quickly in the face of hashpower changes.

HFP0 tackles this problem by replacing the historic, every-2016-blocks retargeting algorithm with a much more responsive, per-block algorithm - the Multi Interval Difficulty Adjustment System (MIDAS). MIDAS was specifically designed to help a coin survive large fluctuations in hashpower and timewarp attacks such as the Zeitgeist attack performed against Geistgeld and similar attacks against other coins.

There has been a lot of discussion about whether the "magic number" of 2016 blocks in Bitcoin's block retargeting interval actually serves some useful purpose. It equates to roughly 2 weeks (14 days @ 144 blocks/day). It has the observable effect that Bitcoin reacts quite slowly to changes in hashpower, which is good for the established chain and dominant miners, but makes life difficult for a fledgling spin-off.

It seems there isn't anything special about the 2016-block interval. One argument raised in its favor (other than "because that's what Satoshi picked") is that it provides a form of planning security for miners and pools. I'm not convinced. Surely having more up-to-date information on the actual trend in hashpower is more valuable than not having that information, and instead having a growing uncertainty as time goes on? If you have come across a more convincing logical argument, please let me know.

I don't believe Satoshi intended the long interval as a defense against rival hard forks, but I'm open to correction (please provide a citation).

What surprised me, from discussions within BTCfork, is that quite a few developers are fond enough of the 2016 number to want to keep it around, or at least re-converge to it soon after a fork. I think that's risky. There is no crystal ball that can predict when the hashrate will stabilize. Whatever number or algorithm you pick to converge back to the status quo - adversaries can exploit it after studying your fork code and waiting the required amount of time before attacking.

Recalculating on every block allows maximal responsiveness to whichever algorithm you pick, which is where the defensive strength lies. It also doesn't cost much in terms of performance. Compared to the other block validation computations, the difficulty retargeting overhead is insignificant even for a more complex algorithm such as MIDAS.

Per-block retargeting is used successfully in many well-known coins (Ethereum, Monero, Dash, Dogecoin) with various algorithms (e.g. Dash's Dark Gravity Wave v3, Dogecoin's DigiShield, etc). Some of these coins have much faster block periods than Bitcoin's 10 minute average. Therefore it is clear that per-block retargeting is not inherently flawed and scales down to even small block periods (not that I'm suggesting we should change the block period at this stage).

2. Adaptive block size cap

From the outset, HFP0 was intended to support a block size larger than Classic's 2MB.

To prevent a situation where an attacker could spam the network with huge blocks consisting only of their own transactions, I wanted to include an algorithm to dynamically adjust the maximum block size between some lower and upper bound, based on network demand.

BitPay had earlier presented their thoughts and a design for an adaptive block size algorithm which adjusted the maximum block size based on the median block size in a historic window. They implemented it to study its performance w.r.t. historical block size data and the results were quite encouraging.

I liked this simple algorithm proposal from the start, because its core design was virtually identical to the median-based algorithm used in Monero (although Monero goes further and adjusts the block reward if the block size exceeds a minimum median size). I am not a fan of flexcap-like proposals. By changing Bitcoin's rather elegant and simple incentive structure, they could introduce unforeseen economic consequences. So far, I haven't seen any studies which refute BitPay's findings that their adaptive block size proposal could work well for Bitcoin and public opinion of it seemed quite favorable since its release.

The BitPay adaptive block size algorithm is a good choice for a fork which doesn't completely abolish the block size cap, but wants to offer a pathway to significantly larger blocks. An algorithmically controlled block size cap is much easier to come to terms with than Bitcoin Unlimited's radical concept of "emergent consensus".

Nowadays, I think BU's concept is more widely understood than it was in early 2016, which is reflected in the increasing support among users and miners. An overwhelming majority of respondents in a Reddit poll recently voted BU as their favored baseline client for BTCfork's MVF implementation.

HFP0 modifies BitPay's adaptive algorithm slightly to provide a raised floor of 2MB (instead of the historic 1MB). I've also added a ceiling of 4MB, since 4MB has been described as relatively safe in the Cornell study on block propagation.

Soft-limit scaling has been disabled for simplicity reasons (the configured soft limit is used as-is). A production-ready spin-off using of BitPay's algorithm would almost certainly provide automatic soft-limit scaling.

3. Improved block propagation using Xtreme Thinblocks

The traditional block diffusion method in Bitcoin is not optimal as it transfers uncompressed block data all the time.

For a small increase in the block size, such as from 1MB to 2MB, this would be hardly noticeable. Studies have shown that as the block size increases, propagation within the network becomes increasingly problematic, although at sizes up to 4MB, 90% of the nodes measured could cope without problems.

The block propagation bottleneck had been known for quite some time and major clients have all added improved block propagation methods:

  • Bitcoin XT's thinblocks implementation
  • Bitcoin Unlimited's Xtreme Thinblocks (Xthinblocks)
  • Bitcoin Core's CompactBlocks

Before working on this fork, I had briefly started to look at yet another block propagation improvement idea - Jonathan Toomim's 'blocktorrent' concept. I decided that working on a hard fork was more urgent, as Xthinblocks were already in good shape and a further block propagation algorithm would provide only marginal improvement. However, the main projects were not focused on providing a guaranteed (non-elective) alternative plan to Core's soft-fork-riddled roadmap, in case the BIP109 election strategy failed or some other unforeseen disaster (e.g. Fee Event, Halving Death Spiral) were to befall due to 1MB blocks filling up as predicted.

While I was working on HFP0, Bitcoin Unlimited's Xthinblocks were already proving themselves in the field. I witnessed firsthand the bandwidth savings on my Unlimited node. I was impressed and confident that Xthinblocks could easily handle fast propagation of larger blocks, preventing adverse affects on the network even if consumer-grade connectivity was assumed. The Bitcoin Unlimited team has since rigorously demonstrated the beneficial effects on latency and bandwidth in a well-received experiment conducted across the Great Firewall of China.

Rusty Loy ported the Xthinblocks implementation over to Bitcoin Classic 0.12, which was fortunate since it meant I didn't have to port it directly from BU myself, but could instead integrate his code quite easily into HFP0.

When CompactBlocks were announced by Core, I didn't see enough additional value over Xthinblocks to merit integrating them, especially as a spin-off would at first not need to interoperate with other clients.

Minor improvements

4. More effective network separation

HFP0 separates from other-chain peers more effectively than the final version of satoshisbitcoin did. In fact this seems to have been one of the remaining open issues after satoshisbitcoin's last public test.

Recent discussions with members of the BTCfork development community have convinced me that HFP0 is still messier in this regard than it should be. I elaborate on this in the section 'Missing items' below.

5. Disabling of alert system

The alert system has been disabled. If the command line option or configuration file option is enabled, the client prints a message that the system is deprecated and disabled.

The alert system was initially considered in satoshisbitcoin as a tool to help with fork separation.

However, Core and other clients have subsequently removed it and there is no good reason for a spin-off to keep it around. It just introduces an issue of centralized alert key management. As it turned out, that didn't work out well the last time.

The obsolete alert system code in HFP0 was intended to be completely removed in a later clean-up update.

6. Backport activated soft-forks

BIPs 65, 68, 112 and 113 were considered necessary as they are already active on the main chain.

Missing items

This fork prototype lacks several features which should be implemented in a finished version.

Some of them should be considered critical - others are not so important or just nice to have.

Urgent

The missing features listed below are what I consider highly important. If left unimplemented, they would in my opinion seriously and unnecessarily endanger the viability of an attempted spin-off.

Replay attack protection (signature change)

This prototype is lacking protection against so-called 'replay attacks'. A replay attack can occur when a malicious actor can pick up transactions on the fly on one network and replay them onto the other (forked) network against the wishes of the transaction sender.

In a spin-off situation, many holders of coins will want to have the ability to transact independently with their pre-fork holdings on the various fork chains. This helps with price finding and boils down to your right as a holder to spend your money where you please, when you please.

To guard against malicious replays, a fork needs to modify the signature scheme, so that only the original sender can produce a valid transaction on either chain.

The initial design I came up with proved inadequate - it prevented replay of transactions only in one direction. It would have still been possible for transactions made using the spin-off client to be replayed on the other chain.

After discussions among BTCfork developers, a better solution seems to have been found. This will be implemented and tested in a future fork prototype (unless analysis reveals a weakness and requires a change of plans).

Proper DNS seeds, static IP seeds

Until now, I've only tested HFP0 in an isolated test environment (although it did include an isolated version of testnet).

In the released HFP0 code, all DNS seeds have been removed and IP seeds replaced by a shortlist of private IPs from my test environment. This is because:

  1. there is no need to bother existing public peers while testing a prototype on an isolated test network
  2. it simplified test activities

A viable spin-off should come with public seeds to get up and running, and so it would need to populate the seed lists with its own addresses.

To make it easier to re-use software builds in various test environment, it would be nice if seed configuration changes did not require a recompilation of the application. That's a nice little task for a rainy day.

Running the prototype without preconfigured peers should work fine, only requiring some additional manual actions (e.g. addnode commands) to establish peer connections.

Review and evaluation of modified POW

The modified scrypt algorithm has been exposed to some informal testing during satoshisbitcoin's public tests and private tests of HFP0.

However it is not known to have received significant code review and rigorous verification.

As this modified scrypt POW is intended to be mined using CPUs, the scrypt variant of HFP0 might be vulnerable to botnet attacks. Further analysis is definitely needed to determine weaknesses and possible improvements.

It may be preferable to exchange the modified scrypt POW algorithm for one that has already been proven in practice. There are several strong GPU algorithms that may bring existing hashpower benefits to a spin-off, however there are also existing mining entities in the Bitcoin space which have significant altcoin GPU mining hashpower alongside their Bitcoin ASIC mining operation.

Backup of pre-fork wallet

After the fork occurs, transactions involving post-fork coins can start to taint the user's wallet file, making it difficult or impossible to spend coins from the wallet with an old-chain client.

It would be sensible to create a backup for user of the wallet file as it existed just prior to the fork. That way the user would have no problem accessing pre-fork coins on the old chain as well.

HFP0 currently does not back up the wallet, instead relying on the user to create their own wallet backup before the fork triggers. Some users will inevitably forget to do such backups, leading to support problems. It's also questionable whether this can be done safely manually, without shutting down the client. Stopping for a wallet backup might not be satisfactory for users who might need to keep on transacting across the fork height. A software feature to assist users is required.

Cleaner network separation

HFP0 does not change the network magic or TCP port at fork time. It remains connected at network level to the old chain's network, processing protocol data that they may send to HFP0 peers.

While it separates slightly better than satoshisbitcoin's final version from the old chain network, the network separation is still deficient.

HFP0 separation relies on the banning of peers which send it old-version blocks after the fork height. At fork time, it switches to a new block version and accepts only blocks of that version (or higher). However, it carries on receiving new blocks even from the old chain, and looks at them to see if they are forked blocks or not. If it sees that that they have the wrong block version, it raises the ban score on the peer that sent it, until that peer eventually becomes disconnected. In turn, the old chain peer would ban the forked peer as well for misbehaving, at the latest when the fork chain peer keeps sending it blocks that have the wrong difficulty or whose has doesn't match SHA256 anymore (for the POW fork chain).

A better fork design would change the network magic. This would significantly reduce the amount of unnecessary processing it does on packets that come from the old chain. An attacker would have to spoof the network magic to feed protocol packets to the new chain, otherwise it would just not process them further.

Even better would be if the fork disconnected cleanly from non-fork peers (without the banning drama). But how to reconnect only to the peers of your fork? Can you tell them apart from the other clients that are not aware of your fork, that you may not want to connect to? It becomes a little complex.

To simplify that complexity, all fork-aware (and fork-compatible) clients could move together to a separate network port, forming their own Bitcoin peer network disconnected from the existing one. This requires a little more code - you have to cleanly disconnect, close network sockets, open new ones, reconnect to peers etc. That comes with risks of its own:

  • you have to have enough fork peers in your peer list, or use somewhat centralized, publicly visible discovery mechanisms (DNS seeds, perhaps some onion service) which can be attacked
  • at least you know that the existing Bitcoin TCP port is already available on your system because you were running on it -- a new port might already be bound by another application on some systems

Despite the complications, a cleaner separation is certainly possible, and it would be worth investing some effort to mitigate risks and avoid negative impacts on both sides of the network.

HFP0 also changes the P2P protocol version (different versions used depending on POW/non-POW variant). However, it does not use the protocol version to ban peers after forking. The protocol version was initially changed with that idea in mind, but I abandoned that as a peer should be able to talk to peers with other protocol versions as freely as possible. So the HFP0 protocol versions are just informational, like the user agent string, to be able to recognize it on the network.

Better peers/banlist datafile handling

HFP0 does not clean up or write to a separate, new peers.dat file. This is an area where satoshisbitcoin was slighly better. It switched to a new peers file (forked_peers.dat) at the fork. My view is that it should have backed up the pre-fork peers.dat file under a different name, e.g. oldpeers.dat, and then carried on using peers.dat as the active peers filename.

As I didn't like the way satoshisbitcoin implemented the switchover, I've removed it in HFP0.

I think files like peers.dat and banlist.dat are de-facto well-known interfaces which should be maintained unless there is a compelling reason. These files are widely documented using their specific names / locations, and configured in backup scripts and other miscellaneous procedures developed by users of the Bitcoin software. Changing the active locations violates the principle of least surprise. Imagine if every fork abandoned them in a different way!

In this case, it shouldn't be too hard to just back them up as-is under a different name, and then keep using the old location for the active file. It's less painful to document once where you create a backup, instead of breaking all user-related documentation.

Complete test coverage

HFP0 test coverage is inadequate, which is forgivable in the case of a prototype where someone is learning the code and trying out various things, but it would be unacceptable for a serious spin-off attempt.

Here is a list of HFP0's current shortcomings w.r.t. its own additions:

  • MIDAS is missing unit and integration/regression tests.
  • The hard fork trigger tests need to check more thoroughly around the trigger height, and in re-org circumstances.
  • The big block aspects need an overhaul to test right up to the 4MB ceiling.
  • The BitPay adaptive block size feature needs an integration test, not just unit testing.

With upcoming fork developments under the BTCfork umbrella, we intend to specify changes in terms of proper requirements and better documented design, which should make it easier to implement tests and expose areas that lack verification.

Known Bugs that need fixing

HFP0 likely contains a few bugs. Two existing tests are known to fail and need to be fixed:

  • bip68-sequence
  • pruning

The first failure (bip68-sequence) might be unrelated to the fork changes, or due to code which I might not have merged carefully enough. I haven't been able to identify the exact fixes, but similar problems were observed with that test on Classic v0.12, and have since been fixed in Classic v1.1.0.

The pruning test failure looks like it might fail due to re-org problems. These would be a consequence of fork-related changes. Troubleshooting is painfully slow because of the long running time of the test.

A possible (unconfirmed) bug is the continued usage of the old max block size when creating an instance of the ValidationCostTracker in src/main.cpp:

ValidationCostTracker costTracker(OLD_MAX_BLOCK_SIGOPS, MAX_BLOCK_SIGHASH);

At the time of adapting the code, I was unsure whether the dynamically calculated block sigops value could be safely used. I've marked that as a possible bug using a TODO.

Non-urgent omissions

These are bits and pieces which are unfinished but seem less urgent.

Scaling of soft block size limit

The optional automatic soft limit scaling feature of BitPay's algorithm was disabled due to time constraints. HFP0 uses the configured soft limit if the -blockmaxsize option is provided.

Automatic scaling would be a useful feature to re-enable - it should require limited effort to implement, test and document.

As it is, miners could work around the lack of auto-scaling by adjusting their soft limits periodically.

Removal of unnecessary debug traces

I've left debug traces in the source in case someone wishes to use them to help with understanding HFP0's workings. All new traces should be guarded by #ifdef conditionals which can be selectively enabled by definitions in consensus.h.

Some of the traces were helpful in troubleshooting certain problems, even with a debugger. A lot of things can go wrong on transactions, problems in that domain were were particularly gnarly to debug, so I added some traces for that.

Better informational output

There is no informational output available via the getblockchaininfo RPC call.

It would be nice to provide an indication about how many blocks are left before the block-height fork triggers.

Resolution of remaining TODOs

If you search the code for the regular expression 'HFP0.*TODO', you will find quite a few TODO items scattered around.

Below I summarize the more important ones which haven't been mentioned above and would require resolution for a fork:

  • POW and non-POW variants might benefit from having their own distinct POW limits. I have tested before on a walled-off instance of testnet, and the current POW limit (which is used to reset the difficulty at fork time) worked well enough for my desktop PC to mine blocks at a reasonable 'few minutes per block' initial rate.
  • POW limits should be calibrated.
  • Minor cleanups from Bitcoin Classic's BIP109, replacing with block-height hardfork appropriate equivalents. For example, the sizeForkTime variable is a leftover which should be removed. It is still used in code path triggered by getblockchaininfo RPC call.

Code cleanups

A few possible refactorings and cleanups would be advisable.

  • More global variables introduced as part of the adaptive blocksize feature.
  • The added debugging traces could be removed.
  • Clean up the mixture of C/C++ style comments where HFP0 was responsible for creating a mess.

Adapt the bitcoin-tx tool in case of signature changes

This tool would need to be enhanced to optionally emit modified transaction signatures, in case replay attack prevention is implemented using signature change. Otherwise it will not be able to generate valid transaction signatures for the post-fork chain.


In the third and final part of this article, I will look in more detail at the code changes.

Feedback

If you wish to provide feedback or ask questions about HFP0, I've opened a Reddit thread at /r/btcfork to gather comments and questions.

The BTCfork community welcomes everyone who wants to enable a hard fork to join in the discussion. We meet up on various forums and chat channels to discuss and collaborate on matters related to hard forks:

Please refer to the BTCfork website for more information on how to contribute.

Posted Wed 21 Sep 2016 11:00:00 CEST Tags:
8th- to 9th-century molded bronze forks from present-day Iran.
Photo by Marie-Lan Nguyen via Wikimedia Commons.
photo of farmers carrying hay on pitchforks

hardfork_prototype_0 - an early prototype of a Bitcoin hard fork

Part 1 - Introduction

This is a 3-part article which describes an early prototype of a Bitcoin spin-off, called "hard fork prototype 0" (HFP0, for short). A spin-off is a special type of hard fork (HF) which preserves the entire ledger up to the point in time where it diverges to become its own currency.

The parts of this article progress from a general overview to deeper technical explanation:

  • Part 1 (this post): introduction, history
  • Part 2: high-level technical overview
  • Part 3: detailed technical walkthrough

The HFP0 source code has been published along with these articles. This prototype is based on Bitcoin Classic v0.12.0cl1 (this commit, to be precise) and was inspired by an earlier hard fork prototype, (satoshisbitcoin), which was written by user 'rocks' on the United Bitcoin Community's Bitcoin Forum. I heartily recommend joining that forum if you're interested in gaining deeper knowledge of Bitcoin and the economic aspects of cryptocurrencies.

In March 2016 I started working on what became HFP0. I had planned to release it alongside satoshisbitcoin as a complementary spin-off which would not change Bitcoin's proof-of-work (POW) function, because I thought it would be worthwhile to offer a true hard fork which the existing miners could still support, if they wanted. The other aim was to familiarize myself with the Bitcoin source code and development process. That's why free software is free and open after all - if you don't like the way things are heading, you can pick up the code, learn about it and implement the features you want.

Even before the Ethereum fork, I discussed the need for protection against replay attacks. The ETH/ETC fork finally convinced me that a serious Bitcoin spin-off attempt would require a robust solution to this problem. Furthermore, any spin-off would require substantial support and engagement from the community to get off the ground. As it happened, members of the community created BTCfork, an organization consisting of Bitcoin users from all walks of life and professional backgrounds, united in their desire to hard-fork Bitcoin to restore the original vision of Satoshi: Bitcoin: a peer-to-peer electronic cash system.

The next two parts of the article will delve into the technical aspects of HFP0. I encourage those who are interested to study and play with HFP0, and use whichever parts of it they see fit for their own hard fork experiments, just as I learned and used code from satoshisbitcoin. There are some additions that may yet be of value, such as the per-block retargeting algorithm (Ray Dillinger's MIDAS) and the more 'realistic' implementation of BitPay's adaptive block size algorithm.

If you wish to provide feedback or ask questions about HFP0, I've opened a Reddit thread in /r/btcfork to gather comments and questions.

The BTCfork community welcomes everyone who wants to enable a hard fork to join in the discussion. We meet up on various forums and chat channels to discuss and collaborate on matters related to hard forks:

Please refer to the BTCfork website for more information on how to contribute.

Why not spin off right now using this code?

HFP0 is not ready for production use. That's why I'm calling it a prototype, and releasing only source code.

It lacks a feature which developers in BTCfork, including myself, have identified as a critical requirement for a viable spin-off:

  • protection against replay attacks by making the forked transaction signatures invalid on the old chain

A lack of replay attack protection led to complications in the recent Ethereum hard fork. Althought the ETH/ETC fork was very different in many respects from what a planned HF in Bitcoin would be like, it highlighted the importance of protecting against replay attacks.

I believe that the viability of an attempted Bitcoin spin-off would be seriously compromised if it failed to provide replay attack protection. My initial solution design turned out to be inadequate, but a better solution has since been proposed and will be implemented and tested in future forks.

There are other features missing in this prototype that a safe hard fork should implement:

  • clean separation of the networks to avoid unnecessary processing on both sides
  • creating a backup of the user's hot wallet prior to the fork, for use with an unmodified (old chain) client, to ensure user can access his entire pre-fork holdings on the old chain without problems

There are further issues around the release and deployment of a spin-off that need to be managed carefully. Without extensive quality assurance (testing), sufficient public exposure (incl. preparation time) or build-up of critical infrastructure and supportive relationships with prospective miners, pools, exchanges, wallet manufacturers, a spin-off would start with a potentially fatal disadvantage compared to the incumbent Bitcoin implementation.

More detail on other shortcomings of this prototype will be presented in the remaining parts (see Technical Overview and Details).

History of this project

I have been following Bitcoin's block size debate for quite some time on various forums, starting in /r/Bitcoin (nowadays I would recommend /r/btc).

After several elective (i.e. voting-based) hard fork proposals went nowhere due to a minority of Bitcoin users, the miners, vetoing Bitcoin Improvement Proposals (BIPs 101,109) and unknown criminal elements employing 'dirty tricks' against the network infrastructure of such forks (e.g. denial-of-service attacks against their nodes), I became determined to involve myself in development of a non-elective hard-fork as described by Satoshi. I wanted to give the market freedom of choice on the issue of block size, and that it was the only way to overcome what I perceive to be a corporate capture of the decision-making power in terms of where Bitcoin's development is headed.

I took particular interest in the satoshisbitcoin fork development in the Bitcoin Forum, and participated in the public testing of that client, which revealed some needed improvements.

The original purpose of my fork was to offer a complementary spin-off which retained Bitcoin's traditional SHA256 POW and was to be based on a more recent Classic 0.12 codebase (satoshisbitcoin was based on Classic 0.11.2 which lacked some optimizations such as libsecp256k-based signature validation).

Satoshisbitcoin's author disappeared from the Bitcoin Forum around mid-April 2016, leaving that fork software unmaintained. I decided to absorb the POW-change functionality into my actively developed fork, making it possible to build both a POW and a non-POW version of my fork, as it seemed important to offer the choice to the market in the event of a hard fork situation. I recognize that a lot of money has been invested in Bitcoin's mining infrastructure by many individuals as well as companies. Giving existing miners the option of supporting a hard fork by mining the unchanged-POW version using their existing equipment would lower the risk to the currency's security. Then the market would be able to decide whether to support the miners or not, without having to make a binary choice between the existing miners and the fork's actual improvements. It is important for the health of the Bitcoin ecosystem that decisions on critical issues are opened up to independent choice. As with a referendum, there is a danger of confusing the performance of the incumbent miners with the issue on which the referendum is being held - in this case the block size.

Starting from the premise of supporting the existing POW, my fork needed changes which satoshisbitcoin did not strictly require, such as modifying the difficulty adjustment algorithm to defend against attacks by the existing miners. Also, I wanted it to support blocks bigger than 2MB, leading to the addition of BitPay's adaptive block size algorithm (modified to have a 2MB floor and 4MB ceiling) and Bitcoin Unlimited's Xtreme Thinblocks for improved block propagation.

On this road, which I started on with zero knowledge of the Bitcoin code, I encountered the help of many generous developers and non-developers who willingly shared what they knew about Bitcoin, its code and other aspects. The list is too long to mention specific names, but I'm grateful to all the Bitcoin Unlimited, Bitcoin XT, Bitcoin Classic and Iguana developers who have helped me when I had questions, as I am to all the Bitcoin Forum members who gave input and advice on matters related to forking.

Participating in BTCfork and /r/btcfork has taught me more about what constitutes a viable, safer hard fork client. Since then my efforts have been focused on developing the requirements, design and implementation of a Minimum Viable Fork in a truly public way, as I believe it should be done to engender the necessary confidence of the wider Bitcoin community for a hard fork.

I think it is appropriate that I now publish HFP0 as it is and for what it is - a step on the road to Bitcoin's eventual first hard fork, and perhaps something that others can use as inspiration and study, just like I was able to do with satoshisbitcoin.

I will provide a description of the technical details and the shortcomings of HFP0 in the subsequent parts (Technical Overview and Details).

The back story - the block size debate

This fork code is part of a bigger story, the block size debate. Software projects sometimes split up when members find themselves holding different opinions about the directions in which the project should go. Bitcoin users have, since 2012, slowly divided into two discernable camps:

  • a group who believes Bitcoin should remain P2P electronic cash, scaling its transaction rate and growing its user base through an increase of its current 1MB block size limit to a value exceeding transactional demand by a safe margin, and removing the limits in its protocol altogether where possible
  • a group who believes that Bitcoin should become more like a settlement system (few transactions, higher fees), with the payment function (fast, cheap fees) offloaded onto additional layers above it (Lightning Network) or sidechains

My opinions align strongly with the first group. I believe that Bitcoin can scale on-chain quite significantly, and should do so to reach as many people as possible, giving them access to secure, disintermediated p2p electronic cash and a world of new services that can arise from this "magical Internet money".

Like many supporters of this view, I am not against exploring alternative methods to scale Bitcoin, such as the Lightning Network, sidechains etc. I strongly disagree with the way in which a roadmap for Bitcoin has been unilaterally imposed on Bitcoin by the Core developers, the most senior and influential of whom have incorporated as Blockstream, and have dismissed many prominent early Bitcoin developers and users who have been lobbying for an increase of the block size cap to prevent economic damage to Bitcoin as blocks have predictably grown fuller, fees increased and network confirmation times grown larger over time. The Core developers have shown no willingness to compromise on the block size issue at all.

This is leaving the advocates of on-chain scaling no choice but to go their own way - a hard fork - the equivalent of a divorce in free software projects.

What makes a cryptocurrency valuable is not only its technical feature set, but its distributed ledger which tracks the real-world distribution of the coins. There are countless new currencies which start from scratch, with an empty ledger.

However, if we want to hard-fork to upgrade Bitcoin's capabilities, it makes sense to preserve the distribution of everyone's coins, i.e. spin-off using the existing ledger. This still results in two currencies ("old" and "new" Bitcoin) from a certain point onwards, but like in a share split, everyone who owns bitcoins before the fork will have the same amount of coins available on the both sides of the fork (the existing currency and the new one) afterwards.

The value of the coins on the new fork may initially be substantially less than those of the original Bitcoin, but from then on it's up to the market to price them according to the value people see in the new currency. If the new currency provides the same features - and more - it could replace the old one.

It takes some consideration to understand that this process of spinning off is not harmful, but beneficial in multiple ways.

  1. it presents a more inclusive method of governing the evolution of the protocol
  2. it is an intrinsic defense mechanism to protect against capture by any subset of its economic actors (anyone can fork at any time)
  3. it allows using fixed time plans to upgrade instead of uncertain threshold voting

I believe these reasons are strong enough for hard forking to become the preferred means of upgrading Bitcoin. Several of the top cryptocurrency contenders (Ethereum, Monero, Dash etc.) fork hard successfully on a regular basis, demonstrating that much of the fear that has been spread around hard forks is unjustified.

Quo vadis?

My focus now will be to use the knowledge I've gained in developing this prototype to work on better fork implementations, following the BTCfork roadmap.

The first priority will be to assist the BTCfork project in the open development of a Minimum Viable Fork (MVF) - i.e. a spin-off which includes only a minimal set of changes and yet strives to be viable. Requirements and design of such a fork are being specified in collaboration with the wider community, and implementation will proceed shortly, based on the input from many supportive developers.

At the same time, I'll collaborate with others to bring about more fully-featured spin-offs which add features voted as desirable by the community.

These spin-offs will venture beyond the MVF requirements in their feature sets, providing for example:

  • block sizes > 2MB
  • better defensive mechanisms (e.g. against DDOS and hashrate-based attacks)
  • improved output to assist users to transact more safely in the expected turbulent period after the fork

Guiding principles behind my fork development efforts

In implementing HFP0 and my future work towards an initial spin-off of Bitcoin, I want to preserve what I feel are important qualities of the current protocol. Some are economically important, some are there for technical reasons, to ensure the secure and safe operation of the system in the context of current infrastructure realities. I believe the technical ones could well be changed by forks in the far future (several years out), once Bitcoin scaling is on a good track and other aspects such as faster confirmation times move into the spotlight.

Principle Reason
Preserve the 21M coin limit This is a fundamental principle of Bitcoin and part of its attractiveness, that the total supply will be limited. A spin-off that changes this would alter the economic premise entirely
Preserve the existing ledger There are enough altcoins that start a new ledger. A spin-off is fundamentally not about taking ownership away (even in the form of requiring new investment in a new ledger), but enabling existing participants to exercise choice on the protocol running the existing ledger.
Preserve the Nakamoto consensus (valid chain with most proof-of-work) This is part of Bitcoin's security model, and should be unchanged by a spin-off.
Preserve the 10 minute block period Lowering this parameter could interfere with safe block propagation, and requires changing other parameters (e.g. block reward) to compensate to keep the economics unchanged. The complicated set of parameter changes would have downstream impact on other systems and should better not be mixed with an initial fork to increase the block size.
Preserve the halving schedule The Bitcoin halving is an important factor in the existing design, and changing it requires careful consideration due to dependencies with other parameters. At the very least, it attracts great public attention to the Bitcoin market periodically.
Preserve the P2P qualities of the protocol Bitcoin's peer-to-peer nature is one of its great achievements and drawing points. Changing this by introducing some form of centralization would endanger public interest in Bitcoin.

As there is divergence of opinion in the community on whether it is preferable for a spin-off to change the POW, it makes sense that both options should be put to the market to decide. They each have advantages/disadvantages, and which way the market decides will probably depend significantly on the behavior of the existing miners and developers in the run-up to hard fork deployments.

SHA256
variant
Modified POW
variant
Advantages
+ simple, secure, proven algorithm + re-decentralize mining (lowers the barrier of entry to participate as miners)
+ capitalize on existing ASIC hashing power + reduce likelihood of future ASIC development, thereby discouraging centralization
+ allows existing miners to support the spin-off + can enforce political change if miners have formed cartel
Disadvantages - exposure to hashpower attacks - more complex algorithm, potentially vulnerable in new ways
- no real chance of general public participation in mining the fork due to ASICs ramping up the difficulty - reduced security compared to ASICs
- reserves seats for existing mining establishment, potentially allowing existing politics to continue - impacts on existing mining hardware investments

HFP0 supports both variants through the use of a new configuration parameter: --disable-newpow .

By default, it builds with a modified POW based on Colin Percival's well-known scrypt algorithm (see also RFC 7914), which is also used by several other cryptocurrencies. HFP0 uses the modified scrypt implemented by satoshisbitcoin - refer to src/crypto/modified_scrypt_* .

By configuring the build with --disable-newpow, the new POW is completely disabled and the existing SHA256 is used.

Posted Wed 21 Sep 2016 12:00:00 CEST Tags: