Back in 2016 I had the idea for a silly joke cryptocurrency for my maniacal panther pal Snowy. I wanted to fork Bitcoin and then modify it so that all coins created would go to a single wallet controlled by Snowy and any transactions would result in the currency going to Snowy's wallet as well. In essence: all money would be Snowy's, as it should be.
I left that in my ideas folder for about 3 years but finally decided to re-investigate the concept.
I'm not entirely sure why I chose to modify Bitcoin over any other available cryptocurrency on the market. Probably as I had the most familiarity with it and had watched it grow and evolve over the years. In retrospect, picking something this mature (and with all the complexities maturity brings) in a language I am not very familiar with (C++), was my biggest mistake.
I did find an excellent series of tutorials that would give me a place to get started. How To Fork Bitcoin (part 1, 2, 3) gave me some great places to start looking when modifying the Bitcoin Core repository.
Props as usual go to StackExchange for all their existing answers on ECDSA key pairs and various other minutiae, as well as the Bitcoin developer reference and various forum answers scattered over the internet.
I started by following the guide linked above and adjusting the following:
- Address prefixes
- Message prefix bytes
- RPC and P2P ports
- Activate BIPs
- Checkpoint data
- Genesis block
- Allow pre-mine spend
At this point I had a fully-functional cryptocurrency on a separate network using slightly modified headers/prefixes to Bitcoin so they could not intefere with each other. I compiled the code and tested it and everything worked as much as I understood it. It was around this time that I started getting a bit more confused about a bunch of the terminology, such as wallets, addresses, keys, etc and how they all interrelated. Worst still, it felt difficult using the existing
bitcoin-cli tool to extract the information I needed.
It is very not user friendly.
Making A Wallet
Part of setting up a cryptocurrency is having a wallet to put all the coins in, so what good is our theoretical Snowy-only coin if he doesn't have a wallet to put all his funds in? To quickly generate one we used OpenSSL:
openssl ecparam -genkey -name secp256k1 -out secp256k1.priv openssl ec -in secp256k1.priv -pubout -out secp256k1.pub openssl ec -in secp256k1.priv -outform DER|tail -c +8|head -c 32|xxd -p -c 32 > bitcoin.priv openssl ec -in secp256k1.priv -pubout -outform DER|tail -c 65|xxd -p -c 65 > bitcoin.pub
One issue we ran into was turning out 256-bit private key into WIF (Wallet Import Format), but thankfully there's a great little guide available with included code snippets.
When we needed to create/mine a genesis block (the initial block in the “blockchain” ledger), we used the
cpp_miner tool supplied by the writer of the guides linked above. We needed to make a few modifications to get it to compile on macOS to fix some C++11 casting errors (you just need to insert some
static_cast<unsigned char>() wrapping around the
bigIntToHex values). Once that's done, letwe ran it with our wallet public key available in the
bitcoin.pub we created. Next we supplied a message for the first block transaction and an amount of coins to be distributed followed by a timestamp (you can generate one with
date +%s on macOS).
Lastly we needed a target threshold. You can find more information about the target threshold on the Bitcoin developer reference docs but suffice to say we wanted a super easy block, so we went with 0x207FFFFF, the easiest possible difficulty. This would equate to 545259519 in decimal notation.
./cpp_miner genesisgen 041c677ef12afe4413cf8a89f81a5d31c524ee625c9721b20122f4de71b1f7c7e312ea340c12f9ef53fc6030a881d51a861a1ed061033cf491b8341d116f44f614 "WELCOME TO SNOWYCOIN" 1000 1574240210 545259519 0
We received the following results:
block header: 01000000000000000000000000000000000000000000000000000000000000000000000045034d4ad2a13bb8cc58149b762a8255f400349c71708d5568dfcd8c7df0e540d2ffd45dffff7f2002000000 nonce: 0x00000002 block hash: 4a9daefa284047ca843be41004f574208f37223d75b477cf471233134bc40576 merkle root: 40e5f07d8ccddf68558d70719c3400f455822a769b1458ccb83ba1d24a4d0345
All Money Is Property Of Snowy
Of course, having a separate blockchain/cryptocurrency is one thing, but if it's just a duplicate of Bitcoin it doesn't fulfill the needs of the project. So I decided to poke around the code and add in a bunch of code segments wherever transactions to other accounts were mentioned.
Each case looked roughly something like this:
std::vector<unsigned char> vec = ParseHex("041c677ef12afe4413cf8a89f81a5d31c524ee625c9721b20122f4de71b1f7c7e312ea340c12f9ef53fc6030a881d51a861a1ed061033cf491b8341d116f44f614"); CPubKey pubkeysnowy(vec); CScript snowyScript = GetScriptForRawPubKey(pubkeysnowy); CTxOut txout(value, snowyScript);
Basically I used the public key I'd created for Snowy, and then turned it into the script address and used that for the transaction out value. So all transactions should be sending to Snowy. I did the same thing to the coinbase rewards and transaction fees.
I ended up modifying about 6 files (8 changes total):
Afterwards, I compiled it again and tried testing on regnet. Here things started to get murky. Fees still kept getting taken from the transactions I made, but did not get sent to the Snowy account. On top of that there was some weirdness with addresses. After the changes it did look like most money being sent was returned to the Snowy account, however sometimes it appeared to be in two separate addresses, one that had the correct private key, and another (with the remaining premine coins) that seemed to be attached to another private key.
Calling It Quits For Now
At this point I felt like I'd run out of clues and started reaching the limits of my knowledge of Bitcoin and C++. Not to say the project is cancelled though, you can find the current code on my GitHub and I'll leave it there in case I feel enamoured with playing with C++ again. As I said before, I think tackling this project with very mature software in a language I am unfamiliar with was probably not the best approach, but I'm glad I still gave it a shot.
I think if I was to redo the project, I'd consider building something ground-up from a simple tutorial (if such a thing is available for distributed cryptocurrencies) or even just do a basic centralised project as a SnowyBank with some fancy blockchain features.
I feel like I picked up some new information, I definitely learned a lot more about Bitcoin, C++, build systems and compilation, etc.