Bitcoin Forum
October 30, 2020, 06:57:28 PM *
News: Latest Bitcoin Core release: 0.20.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1] 2 3 4 »  All
  Print  
Author Topic: How to make an altcoin.  (Read 11447 times)
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 19, 2015, 05:49:17 AM
Last edit: April 20, 2015, 07:33:46 PM by Cryddit
Merited by supermoney (1)
 #1

Most recent 'Cryptocurrency 101' blog post at

http://dillingers.com/blog/2015/04/18/how-to-make-an-altcoin/

Explains how to adapt the Bitcoin 0.10 sources to make an altcoin.

For educational purposes mostly, although I'm sure it will mean some people make alts that otherwise wouldn't have.  

Here's a paste of the full text article:  Additions and corrections are welcome.


How to make an altcoin

Okay, I’m going to preface this article by asking you two things:

First, WHY do you want to create an altcoin?

This is a starting point.  If you don’t have some original ideas, and the ability to actually read and write C++ code to implement them, then you’re going to create something that can’t do anything Bitcoin can’t do, and in that case there’s no point in releasing it.  So don’t.

If you want to release an altcoin, pump it, get a lot of suckers to invest their money, bribe a cryptocurrency exchange to put up a trading market in it, and then dump a bunch of premined coins on the inflated market and leave all the suckers holding the bag, then “don’t” isn’t quite all the advice I want to give you.  Additionally, “go die in a fire”.

So. If you have a reason to create an altcoin – something you’ve thought of a way to do that won’t ever get into Bitcoin itself and which would enable your ideal cryptocurrency to function in ways Bitcoin can’t – then I have a second question for you.

Can you commit yourself to maintaining a release?

This is serious. If you’re going to release an altcoin, you’re going to have a forty-hour-a-week job supporting it. You’re going to have to spend time every day just reading the code to make sure you know what every part of it does. And you’ll need that knowledge, because you’re going to have to figure out technical problems and make technical fixes, in emergency situations, when some joker attacks your block chain. Bitcoin has some stability because Bitcoin has a majority of the hashing power on the planet devoted to it. Your altcoin isn’t even a fart in a hurricane yet, and your proof-of-work block chain will be subject to attacks that you’re going to have to either anticipate or counter in real time. Reading code every day is preparation. The only way you can find your way around it fast enough to make fixes is if you know it inside and out. Anyway, you can have a full time job, or a social and family life, and maintain a released altcoin – but probably not both, unless you’re one of those people who regards sleep as a wholly inadequate time-wasting substitute for caffeine.

Now, with all that said, this article will cover only the beginning of the process: shamelessly cloning an existing coin. Whatever innovations you intend to make, I can’t anticipate them, so there’s no guide here to making them. You have to read the code until you understand it well enough to make them yourself. For purposes of this article, we’re going to use Bitcoin’s 0.10 source code, we’re going to make a near-clone of it named “Newcoin”, and I’m going to be working with Debian Jessie.

Get the source code
Open up a command line shell. Make a new directory in your home directory named src. It’s where you’ll be working. So your first three command lines are

Code:
cd
mkdir src
cd src

Now use your web browser to go to https://bitcoin.org/en/download, find the button in the lower right corner of the box that says “source code”, and get the archive. Its name should be bitcoin-0.10.0(1).tar.gz. Copy it into your new directory and unpack it using the commands:

Code:
cp ~/Downloads/bitcoin-0.10.0\(1\).tar.gz .
tar xvf bitcoin-0.10.0\(1\).tar.gz
cp -r bitcoin-0.10.0 newcoin

In the above two commands, the backslashes before the parens are because there are actual parentheses in the filename, and if you just type them, your shell will try to interpret the command differently. And the directory ~/Downloads is where stuff lands on my system when I download it with my web browser. If you’ve got yours set up differently, you should adjust the command to use your download directory instead, whatever it’s named.

And the last command makes a clone of the bitcoin-0.10.0 directory named newcoin – with its own copies of all the files you just extracted. You should use whatever you want thename of your new altcoin to be for the name of this directory.

Next, you need to get all the stuff that building Bitcoin depends on. Here’s a sequence of commands to do that.

Get the stuff the code depends on

Code:
su
echo 'deb-src ftp://ftp.us.debian.org/debian/ sid main contrib non-free' >> /etc/apt/sources.list
apt-get update
apt-get build-dep bitcoin
apt-get –install-recommends install libbitcoin-dev
exit
Now, I cheated a little bit here. Debian has a Bitcoin package available in its ‘sid’ distribution, but it doesn’t use the same version of the source code we want to work with. The first line makes you root, because root has the permission to modify sources.list and install packages. It’ll ask for the root password and you need to enter it. The second line changes sources.list to add the sid sources to what’s available to your apt command. The third line tells Debian to download all the meta-information about those sources, so it knows what the build process for these packages require. The fourth and fifth lines tell it to download and install all the stuff you would need to build the sid Bitcoin source code package. But you didn’t download the sid source code package, you downloaded the new source code directly from the site instead. The cheat is that the dependencies are the same, so this is an easy way to get everything you need to build. And the last line is to quit being root.

Test build to make sure you got everything set up
The next step is build Bitcoin just to make sure you got everything. So let’s do that. Here are some more command lines. Some of these may take a few minutes to run to completion; this is normal.
Code:
cd bitcoin-0.10.0
aclocal
automake --add-missing
./configure --with-incompatible-bdb
make
How all that worked. (the Automake system)
aclocal generates a file called ‘aclocal.m4′ which is a bunch of macro definitions and so on that automake works with. There was already an aclocal.m4 in the directory, but it is for a version of automake that probably isn’t the one installed on your Jessie system.

automake –add-missing invokes automake, which uses those macros and the file Makefile.am, which is already there, to create another file named Makefile.in. The –add-missing argument tells it to create a couple of standard macro packages that automake uses, because the Bitcoin sources didn’t provide them; it didn’t need to provide them, because it uses the defaults provided by –add-missing.

Makefile.in specifies what configuration needs to know and do and saves that in a shell script named configure. Then ./configure runs that shell script, which tests a lot of things on your system, finds what’s available to build with and link against, and generally figures out in detail how to build the Bitcoin sources it’s looking at, saving that information in a makefile. The –with-incompatible-bdb argument says it’s okay with you to use a version of the Berkeley database later than the one the original Bitcoin client was built with.

Finally make actually uses the makefile that you just built using ./configure, to build the Bitcoin project.

And if you got all the stuff you needed to build with, the whole process should finish without an error.

Check to make sure your test build worked.
Here’s a couple more command lines to make sure that the build worked, by checking to make sure the executable files it was supposed to build are actually there.

Code:
ls src/bitcoind
ls src/bitcoin-cli
ls src/qt/bitcoin-qt
Got ‘em? Excellent! That means your build environment has everything you need to work with to make an altcoin. So, now that the smoke test is over, it’s time to actually go to the newcoin directory and start making your altcoin. So here are some more command lines:
Start your altcoin by using its name instead of Bitcoin's
Code:
cd ~/src/newcoin
find . -type f -print0 | xargs -0 sed -i 's/bitcoin/newcoin/g'
find . -type f -print0 | xargs -0 sed -i 's/Bitcoin/Newcoin/g'
find . -type f -print0 | xargs -0 sed -i 's/BitCoin/Newcoin/g'
find . -type f -print0 | xargs -0 sed -i 's/BITCOIN/NEWCOIN/g'
find . -type f -print0 | xargs -0 sed -i 's/BTC/NCN/g'
find . -type f -print0 | xargs -0 sed -i 's/btc/NCN/g'
find . -type f -print0 | xargs -0 sed -i 's/Btc/NCN/g'
The first four commands change every occurrence of the string ‘bitcoin’ in four capitalizations to the string ‘newcoin’ in all the files in this directory or under it, in three different capitalizations. The second three commands do the same thing to the string ‘btc’, transforming every instance of it into all-caps.

Rename 'bitcoin' filenames to the name of your altcoin
Now, because this also affected makefiles which contain filenames, and affected source files which have filenames in their include statements, you’ve got to change all the filenames that have the string ‘bitcoin’ in them to match what’s now in the include statements and makefiles. Fortunately, this is just as easy.
Code:
find . -exec rename 's/bitcoin/newcoin/' {} ";"
find . -exec rename 's/btc/NCN/' {} ";"
Will rename every file that has ‘bitcoin’ or ‘btc’ in the name, recursing into subdirectories as needed. So now your filenames match up with your changed makefiles and include statements.


Check for stuff your edits missed because it was misspelled.
Now look for misspellings of it.
Code:
grep -ir bitc
Aside from uncovering a bunch of references in source code to nDebitCached and a few similarly named variables, reveals that in Arabic translations ‘Bitcoin’ was rendered as ‘Bitcion’ in several translated sentences. In Dutch, it mentions a "bitcon:-URI", and it became ‘Bitconi’ once in a language I don’t recognize at all but which may be Estonian.

The Dutch is certainly a misspelling, because URI’s are spelled the same regardless of language. So
Code:
sed -i 's/bitcon/newcoin/' src/qt/locale/newcoin_da.ts
sorts that.

I remember about Arabic that it inflects words using patterns of triple vowels, and ‘bitcion’ is used more than once, so it might not be a misspelling. A quick check on Google, however, reveals a lot of instances of ‘Bitcoin’ misspelled in English, and no Arabic pages. So with more evidence, I think I’ll conclude that it probably is a misspelling – about which, again, there’s a chance I’m wrong, and if ‘newcoin’ were what you were actually naming your new alt, you should write on your list of things to do asking someone who actually speaks Arabic about it. But for now patch it using
Code:
sed -i 's/bitcion/newcoin/' src/qt/locale/newcoin_ar.ts
And then there’s the Estonian-or-whatever-it-is. I haven’t heard of any languages outside the middle east that inflect by modifying vowel sequences, and ‘Bitconi’ seems likely to be a misspelling, so once more I’ll just make a possibly-dumb assumption and patch it.
Code:
sed -i 's/Bitconi/Newcoin/' src/qt/locale/newcoin_et.ts
Fix the copyright notices and credits

Now, the license under which you have access to this code mentions, among other things, leaving copyright notices intact – and you mangled ‘em when you switched ‘Bitcoin’ to ‘Newcoin’ because the boilerplate line there refers to the ‘Bitcoin Development Team’. So you need to change ‘Newcoin’ back to ‘Bitcoin’ but only on the lines where it’s part of a copyright statement.
Code:
find . -type f -print0 | xargs -0 sed -i '/opyright/ s/Newcoin/Bitcoin/' {} ";"
sorts that. I left the first letter off of ‘Copyright’ because I didn’t want it to care about the capitalization.

There were also a lot of references to Bitcoin in the release-notes files, and it would be an outright lie to pretend that those earlier releases were releases of your alt rather than releases of Bitcoin, so those need changed back, too.
Code:
sed -i 's/newcoin/bitcoin/g' doc/release-notes/*
sed -i 's/Newcoin/Bitcoin/g' doc/release-notes/*
handles that.

Change the port numbers
Bitcoin uses ports 8332 and 18332 on its main net and 8333 and 18333 on its test net. You want newcoin to use different ports, just to make it handy for people to run both clients at the same time.
Code:
find . -type f -print0 | xargs -0 sed -i 's/8332/9443/' {} ";"
find . -type f -print0 | xargs -0 sed -i 's/8333/9444/' {} ";"
will switch newcoin to using ports 9443 and 19443 on mainnet and 9444 and 19444 on testnet. Once again, you should provide your own values. But don’t change any of the port numbers to anything below 1000, or nobody except root will be able to run it. I should mention here that in addition to the port numbers, you just changed a couple of hex strings in the testing directory that the test framework feeds to the RPC interface. But you were going to fail those tests anyway, because other edits you’re making will make Newcoin keys different from Bitcoin keys.

Use your own artwork
You don’t really want to show Bitcoin’s icons and images every time you start up, so you need to go and edit some graphics in the directory src/qt/res. When editing, be sure to save new images that are exactly the same size and file format as the old ones. When you want to change the sizes and/or file formats, you need to understand the QT framework first.

I don’t have any nifty command lines that can help you make good art, so you’re on your own here. At the very least, you’re going to want to edit newcoin.ico, newcoin.png, newcoin_testnet.ico, newcoin_testnet.png, and newcoin.icns. I suggest using GIMP for all of these edits; it speaks all those graphics formats. The ico and icns files are particularly annoying to deal with because you have to make similar (but not identical) changes on many different layers of the saved image.

Build for the first time
Now we’re done with wholesale edits. It’s time to see whether you broke anything yet. So type
Code:
aclocal;automake --add-missing;./configure --with-incompatible-bdb;make
and wait a few minutes.

Did it build? You now have newcoind, newcoin-cli, and newcoin-qt? Awesome! So now that we managed to get the wholesale edits right, it’s time to actually look at source code and start doing some very specific edits.

In chainparams.cpp, edit the checkpoints

Get your favorite programming editor, go to the newcoin/src/ directory, and open up chainparams.cpp.

Search for the string ‘mapCheckpoints’ and it will take you immediately to line 55, which sets a static variable named mapCheckpoints to a list of pairs – the first member of each pair is the block height, and the second is the hash of that block. The Bitcoin client uses these as it verifies the Bitcoin block chain. So if you leave those in, the newcoin client will be looking for blocks that don’t exist in the newcoin block chain. So get rid of ‘em, and put a place holder for your genesis block in instead. This place holder will be wrong, but we can’t fix it until after we mine a genesis block. After your edit, it should look like this:

Code:
static Checkpoints::MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 0, uint256("0x001"));
Zero is the block height of the genesis block, and uint256(“0×001″) is a wild guess about what the hash is going to be.

Make the same edit at the locations where it sets ‘mapCheckpointsTestnet’ and ‘mapCheckpointsRegtest’.

Edit the Checkpoint Data
Right under each of these edited checkpoint lists, there are statements that set a corresponding variable. These are named data (for the main network), dataTestnet (for the test network), and dataRegtest (for regression testing). Go to the command line and type
Code:
date +%s
to find out what the current unix epoch date is, then overwrite the first number in each of these blocks with the current date. You’ll have to do this again (and mine new genesis blocks) right before launch. The second number in each block is a transaction count as of the most recent checkpoint; it should be replaced by zero, because there are no transactions before the genesis block. The third number doesn’t matter as much, but for now I suggest 500 for the main network, 250 for the test network, and zero for the regtest. Updating these numbers as the amount of traffic on your coin’s block chain changes is one of the things you do as dev, if you want your clients to make accurate estimates of their progress as they reindex or verify the block chain.

Change the protocol 'magic' bytes

The next block after dataRegtest is setting another variable named CMainParams. And you have a lot of things to change here. The first four lines of code set values in an array called pchMessageStart. These are the network ‘magic bytes’; They’re a series of four bytes that identify messages as belonging to a particular protocol. 0xf9, 0xbe, 0xb4, and 0xd9 are the ones Bitcoin uses. You want to use something else, so that nobody can ever trick your newcoin client into connecting to the Bitcoin network, or vice versa. It doesn’t matter what these are except that they shouldn’t match the ones used in other protocols (particularly other cryptocurrency block chains). They have to be values between 0 and 255. I suggest going back to the shell and using
Code:
echo $RANDOM
Just repeat the command, and write down the last three digits whenever they’re under 255. When you’ve got four of them, set the pchMessageStart values in CMainParams. When you’ve got four more, set the pchMessageStart values in CTestNetParams. And when you’ve got four more, set the pchMessageStart values in CRegTestParams.

Make your alert and genesis coinbase keys
The next line (in the first two params objects) sets vAlertPubKey values. So go back to the command line to get some.
Code:
openssl ecparam -genkey -name secp256k1 -out alertkey.pem
openssl ec -in alertkey.pem -text > alertkey.hex
openssl ecparam -genkey -name secp256k1 -out testnetalert.pem
openssl ec -in testnetalert.pem -text > testnetalert.hex
openssl ecparam -genkey -name secp256k1 -out genesiscoinbase.pem
openssl ec -in testnetalert.pem -text > genesiscoinbase.hex
Will create private keys and drop them into files named alertkey.pem, testnetalert.pem, and genesiscoinbase.pem, then expand them into key pairs and drop the key pairs in hex format into files named alertkey.hex, testnetalert.hex, and genesiscoinbase.hex.

Insert your alert keys
Code:
cat alertkey.hex
Will show the contents of alertkey.hex. Copy the four lines that appear between ‘pub’ and ‘ASN1 OID: secp256k1′ and paste them into the source code file replacing the string contents in the line that says vAlertPubKey = ParseHex(“…”);

Then edit to strip the colon characters and linefeeds out of it, and you’ve got an alert key. If you ever need to send an alert out over the network, you can use the corresponding private key.
Code:
cat testnetalert.hex
will show you a key for testnet, so you can set the vAlertPubKey the CTestNetParams block. The CRegTest block doesn’t have one of its own; if it ever needs one, it uses the testnet key.

Edit the timestamp string
Now we skip down to the famous timestamp string, at the line
Code:
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
It’s traditional to pick a newspaper headline for the day of launch, but you don’t have to. Whatever you use, keep it short. If it’s over 90 characters or so the block will fail a length check that’s supposed to prevent denial-of-service attacks from people attaching big data to transactions.

Insert the genesis pubkey.
Code:
cat genesiscoinbase.hex
will show you a key for the genesis coinbase transaction, so you can paste that into the CMainParams block replacing the string contents in the line
Code:
txNew.vout[0].scriptPubKey = CScript() << ParseHex("...") << OP_CHECKSIG;

Set the date in CMainParams
Going down a little more, change the line in the CMainParams block that sets genesis.nTime so that it sets it to the same Unix epoch date you got using the ‘date’ command above. Repeat that edit in the CTestNetParams block.

Delete Bitcoin's seed nodes
Skipping down past the hashGenesisBlock stuff, you’ll see a series of lines that set values for a list named vSeeds. These are network addresses where long-lived Bitcoin nodes are supposed to be found, so that people can always connect to the Bitcoin network. Which, as you’re establishing now, is not your network. Until you put up servers to do that for your new network, replace these lines (in both CMainParams and CTestNetParams) with the simple statements:
Code:
vFixedSeeds.clear();
vSeeds.clear();

Change the Key prefixes
Moving on down, we get to a block of statements that set values in an array of lists named base58Prefixes. These are prefix bytes that are added to the keys. By setting them to different values, you can assure that keys for coins on Newcoin’s network will never be valid Bitcoin keys and vice versa. To a certain extent, setting these numbers also determines what characters the base58 form of the keys that users see starts with. The chances of a random collision in keys are ridiculous, but “chances” and “random” are quaint old-fashioned ideas here; you’re working on code that somebody is going to deliberately attack. So change the values. You can use echo $RANDOM at the command line again if you want. If you care about what initial characters your choices will result in for the base58 form of the keys, consult the list at the Bitcoin wiki. There is one important constraint here: none of the lists can be identical, because the clients look at the initial bytes to figure out what kind of key they’re dealing with. Also, don’t change the length of any list until you’ve read the code enough to know everything that will affect.

PUBKEY_ADDRESS is the value prefixed to public keys – these are the public half of the pubkey/private key pair that represents a txOut and the ability to spend it. SECRET_KEY, predictably, are the prefixes for the private half of the pair. SCRIPT_ADDRESS is affixed to addresses that are the hashes of scripts; looking for the difference between the initial bytes is how the client knows which of the two “default” spend scripts to apply. Finally, EXT_PUBLIC_KEY and EXT_SECRET_KEY are four-byte prefixes for the so-called “stealth addresses” that got introduced in Bitcoin version 0.9, which allow fun things like addresses that can be used to generate new keys that can receive payments but not spend them. Aaaanyway, it doesn’t matter what you change them to, it just matters that they don’t match anything they might ever be confused with, like Bitcoin keys – or each other. So give them new values in CMainParams, CTestNetParams, and CRegTestParams.

Add code to mine a genesis block
Finally, we’re just about ready to mine a Genesis block. But the code to actually mine a Genesis block hasn’t been in Bitcoin for a long time; that block is already mined. Its parameters are there to check against, but there’s no code to establish what some of them ought to be. You need to fix that. So in the CMainParams initializer, right after
Code:
genesis.nNonce = 414098458;
and before
Code:
hashGenesisBlock = genesis.GetHash();
assert(hashGenesisBlock == uint256("....."));
assert(genesis.hashMerkleRoot == uint256("....."));
paste this code:
Code:
hashGenesisBlock = uint256("0x01");
if (true && genesis.GetHash() != hashGenesisBlock)
        {
            Logprintf("recalculating params for mainnet.\n");
            Logprintf("old mainnet genesis nonce: %s\n", genesis.nNonce.ToString().c_str());
            Logprintf("old mainnet genesis hash:  %s\n", hashGenesisBlock.ToString().c_str());
            // deliberately empty for loop finds nonce value.
            for(genesis.nNonce == 0; genesis.GetHash() > bnProofOfWorkLimit; genesis.nNonce++){ }
            Logprintf("new mainnet genesis merkle root: %s\n", genesis.hashMerkleRoot.ToString().c_str());
            Logprintf("new mainnet genesis nonce: %s\n", genesis.nNonce.ToString().c_str());
            Logprintf("new mainnet genesis hash: %s\n", genesis.GetHash().ToString().c_str());
        }
Use the same code in the CTestNetParams initializer, except change ‘mainnet’ into ‘testnet.’ Likewise the CRegTestParams initializer, except change ‘mainnet’ into ‘regtest’.

Now build again. This time you have already done all the autoconf stuff, so you just need to type
Code:
make
and you only changed one file, which isn’t included anywhere else. So it should be built in a few seconds.

Mine the genesis block and insert the new values
Got all that? Now run newcoin-qt.

It will throw up a dialog box asking where to install. Let it have the default it wants, which will be a new subdirectory of your home directory named ~/.newcoin.

Then Nothing will happen.  For twenty minutes to an hour, usually.  Maybe more than an hour, depending on dumb luck and the speed of your computer.  If your computer’s slow, this may be a good time to go get a sandwich.

Here's what's actually happening.  It set the nonce, hashed the genesis block, noticed it didn’t match 0x01, and is now living in that tight little empty for loop, incrementing the hash, hashing the block, and checking to see whether the new hash is low enough to meet proof-of-work requirements.

After a while, it will die. Meaning, it found a nonce that gave the genesis block a hash low enough to pass proof-of-work, got out of the for loop, logged the new hash and nonce and the Merkle tree value, and then hit the assert that still insists on the hash value being Bitcoin’s genesis block hash value. So you want to see the new values. Type
Code:
tail ~/.newcoin/debug.log
and you’ll see the last few lines of logfile output.
Now you have a nonce and a hash and a Merkle root so go change the necessary lines in the CMainNet initializer.

In the code you pasted in, you initialized hashGenesisBlock to uint256("0x01").  Change that to your new genesis hash.

Right above the code you pasted in, you’ll see a line that sets a value for genesis.nNonce. Change it to your new nonce value.

Right below the code you pasted in, you’ll find assert() statements that check the value of the Merkle root and the hash. Change those to your new Merkle root and Hash values.

Near the top of the file, there’s your mapCheckpoints list, claiming that the hash of the genesis block is 0×01. Change that to your new hash value.

Mine the Testnet and Regtest genesis blocks
Once you’ve made these edits, recompile and run it again. The same thing will happen all over, but this time for testnet. And you change the same things in the CTestNetParams initializer (and the testnet checkpoints) that you changed for CMainParams.

Recompile and run it again, and it will trip on the regtest values. So you change the same things in the CRegTestParams initializer.

STOP mining genesis blocks
Okay? Now you have mined your genesis block. Now, in the code you pasted in, see where the stupid-looking if condition checks for
Code:
if (true && genesis.GetHash() != hashGenesisBlock)
?
Change those three ‘true’s to ‘false’s. The purpose of this ‘true/false’ business is to make it easy for you to switch back and forth from mining genesis blocks to not mining genesis blocks. You’ll need to mine a new genesis block right before launch, and may need several more during testing and development depending on whether you do anything that changes the block headers or initial coinbase transaction. But in the client you actually test and release, you don’t want genesis block mining turned on. If it sees a wrong genesis block in its folder, you want it to bomb out immediately, not sit there chewing and trying to create a new one.

Whenever you need to mine new genesis blocks because you changed something that invalidated the old one during development, you can come back to chainparams.cpp, update the date parameter and timestamp string, make the three true/false edits, recompile, do
Code:
rm -rf ~/.newcoin
so it doesn’t see the (now) wrong former genesis block in the data there, and mine new genesis blocks.

What you've got

At this point you have created a complete, and completely simple, clone of Bitcoin version 0.10. If this is all you’re doing, then it’s been a nice learning experience but don’t launch this coin. Unless doing something new, there is no point.

Problems you still need to fix

This thing you have created cannot possibly survive as an altcoin; Aside from having no network seeds of its own, its difficulty adjustment algorithm will not respond quickly enough to prevent your block chain from getting instamined, and then stuck. Mining whales will scoop up two weeks of coins while processing almost no transactions, in less than an hour while your block chain is profitable, then when the difficulty adjustment for that two weeks hits they’ll leave your chain with an impossibly high difficulty and go on to something else. You won’t get a block for days and nobody will be able to use your alt to make any kind of transaction because of it. The result is a block chain that can handle transactions for maybe two hours out of every year, which is useless to everyone.

So the next thing you need to do is go fix that. And when you’ve fixed it, your new alt still won’t be capable of surviving; everybody has fixes for the difficulty problem that a cloned coin creates. Once again, you either have a new idea and the ability to develop and support it, or you don’t have anything that’s worthwhile to launch. What I have shown you here are the first three steps on a long road.

I’ll talk about one way to fix the difficulty in the next installment.
1604084248
Hero Member
*
Offline Offline

Posts: 1604084248

View Profile Personal Message (Offline)

Ignore
1604084248
Reply with quote  #2

1604084248
Report to moderator
1604084248
Hero Member
*
Offline Offline

Posts: 1604084248

View Profile Personal Message (Offline)

Ignore
1604084248
Reply with quote  #2

1604084248
Report to moderator
1604084248
Hero Member
*
Offline Offline

Posts: 1604084248

View Profile Personal Message (Offline)

Ignore
1604084248
Reply with quote  #2

1604084248
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1604084248
Hero Member
*
Offline Offline

Posts: 1604084248

View Profile Personal Message (Offline)

Ignore
1604084248
Reply with quote  #2

1604084248
Report to moderator
Pepijn
Newbie
*
Offline Offline

Activity: 36
Merit: 0


View Profile
April 19, 2015, 06:00:46 AM
 #2

Wall of post. Appreciate you posting though.
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 19, 2015, 07:38:33 AM
Last edit: April 22, 2015, 02:34:14 AM by Cryddit
 #3

I've now put a version of this article on my blog, at: http://dillingers.com/blog/2015/04/21/altcoin-difficulty-adjustment-with-midas/ .  If you quote it or post it elsewhere, please include a link back to that page.

Altcoin Difficulty Adjustment With MIDAS

Okay, I promised I’d give a way to fix the difficulty retargeting issue. Here it is.

Go to the file src/pow.cpp. Delete the function GetNextWorkRequired.

Replace it with the code attached to this post.

MIDAS or Multi Interval Difficulty Adjustment System is my own invention. It responds very well to sudden changes in hashing power whether up or down. Emergency adjustments if needed usually kick in within ten blocks, and in non-emergencies it’s got a responsive but gradual and well-damped adjustment.

Additionally, it makes an effort to keep the block chain height approximately synchronized with real time – although real time here should be thought of more in terms of calendar date than clock time. If it’s more than a couple of weeks behind, MIDAS will be trying to make block times about 10% faster than nominal, and if it’s more than a couple of weeks ahead, it will be trying to make block times about 10% slower than nominal. Inbetween, there’s a linear interpolation between those speeds – meaning the point toward which MIDAS regulates will be exactly the nominal block time whenever it there’s an exact correspondence between block height and real time. Whenever the hashing rate has been reasonably steady for the last month or so, the correspondence between block height and actual time should be within a few hours.

This was originally proposed as a reaction to (and replacement for) the first version of the Kimoto Gravity Well algorithm, which was extremely “twitchy” in that whenever two blocks arrived whose timestamps were too close together, or reversed in sequence, it would make extreme adjustments to the difficulty rate. By checking multiple different intervals and making adjustments only when there is agreement as judged by several intervals as to which way and approximately how extreme the adjustment should be, MIDAS both avoids twitchiness and permits fairly extreme adjustments when they are actually needed.

Because the intervals it checks have no common divisor, it is also extremely resistant to timewarp attacks; there are no “harmonics” for an attacker to exploit that would allow bogus timestamps at particular intervals to reinforce each other leading to spurious adjustments, and no way for a bogus timestamp to cause a disproportional difficulty adjustment.

In my opinion, MIDAS is something that almost every altcoin ought to have; I believe it to be better behaved than anything else I know of that’s in use.

Setting Parameters – Block Intervals

Back in the file ChainParams.cpp, there are some parameters you can change that will change the behavior of your difficulty retargeting. The most important one is nTargetSpacing, in all three of the parameters initializers. For Bitcoin this is set (in all three places) to 600 (10 * 60) because the Bitcoin protocol is built around ten-minute blocks and there are 600 seconds in a block. If you want six-minute blocks for Newcoin, set it to 360 (6 * 60) instead. Most alts make this faster, which tends to centralize mining at places with good connectivity because the shorter the block time is, the more likely the miner is to get an orphan block due to otherwise-insignificant differences in network lag. If you make the block times too short, the network won’t be able to synchronize because blocks won’t even be able to cross the network before

Setting Parameters – Adjustment Interval
The second is the nAdjustmentInterval, which is set directly below nTargetSpacing in all three blocks. MIDAS uses this variable for an entirely different purpose than Bitcoin’s difficulty adjustment algorithm used it for. In MIDAS, this is the period over which the block intervals are regulated +- 10% depending on how far the block height is from correspondence with the timestamps. From Bitcoin’s code this is 60 * 60 * 24 * 7 — one week’s worth of seconds. I’m leaving that value in place.

MIDAS stretches or shrinks blocks slightly as it seeks to make (genesis time + block height * nTargetSpacing) approximately equal to the timestamps of the blocks it’s receiving. nTargetSpacing, or the nominal block time, given our value of 6 minutes, is 360 seconds. In fact, the block intervals that MIDAS will regulate toward range from 324 (360-36) seconds if it’s a full adjustment period or more behind, to 396 (360+36) seconds if it’s a full adjustment period or more ahead. In between, there’s a smooth interpolation, so as long as the correspondence is reasonably close we should never be regulating toward an interval more than a few seconds longer or shorter than 360. If you made the adjustment interval very short, then smaller differences in correspondence would result in greater differences in the block timing MIDAS regulates to achieve. As written, the difference from nominal spacing is limited to ten percent.

The Code:
Code:
// This is MIDAS (Multi Interval Difficulty Adjustment System), a novel getnextwork algorithm.  It responds quickly to
// huge changes in hashing power, is resistant to time warp attacks, and regulates the block rate to keep the block height
// close to the block height expected given the nominal block interval and the elapsed time.  How close the
// correspondence between block height and wall clock time is, depends on how stable the hashing power has been.  Maybe
// Bitcoin can wait 2 weeks between updates but no altcoin can.

// It is important that none of these intervals (5, 7, 9, 17) have any common divisor; eliminating the existence of
// harmonics is an important part of eliminating the effectiveness of timewarp attacks.
void avgRecentTimestamps(const CBlockIndex* pindexLast, int64_t *avgOf5, int64_t *avgOf7, int64_t *avgOf9, int64_t *avgOf17)
{
  int blockoffset = 0;
  int64_t oldblocktime;
  int64_t blocktime;

  *avgOf5 = *avgOf7 = *avgOf9 = *avgOf17 = 0;
  if (pindexLast)
    blocktime = pindexLast->GetBlockTime();
  else blocktime = 0;

  for (blockoffset = 0; blockoffset < 18; blockoffset++)
  {
    oldblocktime = blocktime;
    if (pindexLast)
    {
      pindexLast = pindexLast->pprev;
      blocktime = pindexLast->GetBlockTime();
    }
    else
    { // genesis block or previous
blocktime -= Params().TargetSpacing();
    }
    // for each block, add interval.
    if (blockoffset < 5) *avgOf5 += (oldblocktime - blocktime);
    if (blockoffset < 7) *avgOf7 += (oldblocktime - blocktime);
    if (blockoffset < 9) *avgOf9 += (oldblocktime - blocktime);
    *avgOf17 += (oldblocktime - blocktime);    
  }
  // now we have the sums of the block intervals. Division gets us the averages.
  *avgOf5 /= 5;
  *avgOf7 /= 7;
  *avgOf9 /= 9;
  *avgOf17 /= 17;
}


unsigned int GetNextWorkRequired(const CBlockIndex *pindexLast, const CBlockHeader *pblock)
{
    int64_t avgOf5;
    int64_t avgOf9;
    int64_t avgOf7;
    int64_t avgOf17;
    int64_t toofast;
    int64_t tooslow;
    int64_t difficultyfactor = 10000;
    int64_t now;
    int64_t BlockHeightTime;

    int64_t nFastInterval = (Params().TargetSpacing() * 9 ) / 10; // seconds per block desired when far behind schedule
    int64_t nSlowInterval = (Params().TargetSpacing() * 11) / 10; // seconds per block desired when far ahead of schedule
    int64_t nIntervalDesired;

    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    if (pindexLast == NULL)
        // Genesis Block
        return nProofOfWorkLimit;

    
    if (Params().AllowMinDifficultyBlocks())
    {
        // Special difficulty rule for testnet: If the new block's timestamp is more than 2* TargetSpacing then allow
        // mining of a min-difficulty block.
        if (pblock->nTime > pindexLast->nTime + Params().TargetSpacing() * 2)
           return nProofOfWorkLimit;
        else
        {
            // Return the last non-special-min-difficulty-rules-block
           const CBlockIndex* pindex = pindexLast;
           while (pindex->pprev && pindex->nHeight % nIntervalDesired != 0 && pindex->nBits == nProofOfWorkLimit)
               pindex = pindex->pprev;
           return pindex->nBits;
        }
    }

    // Regulate block times so as to remain synchronized in the long run with the actual time.  The first step is to
    // calculate what interval we want to use as our regulatory goal.  It depends on how far ahead of (or behind)
    // schedule we are.  If we're more than an adjustment period ahead or behind, we use the maximum (nSlowInterval) or minimum
    // (nFastInterval) values; otherwise we calculate a weighted average somewhere in between them.  The closer we are
    // to being exactly on schedule the closer our selected interval will be to our nominal interval (TargetSpacing).

    now = pindexLast->GetBlockTime();
    BlockHeightTime = Params().GenesisBlock().nTime + pindexLast->nHeight * Params().TargetSpacing();
    
    if (now < BlockHeightTime + Params().AdjustmentInterval() && now > BlockHeightTime )
    // ahead of schedule by less than one interval.
nIntervalDesired = ((Params().AdjustmentInterval() - (now - BlockHeightTime)) * Params().TargetSpacing() +  
   (now - BlockHeightTime) * nFastInterval) / Params().AdjustmentInterval();
    else if (now + Params().AdjustmentInterval() > BlockHeightTime && now < BlockHeightTime)
    // behind schedule by less than one interval.
nIntervalDesired = ((Params().AdjustmentInterval() - (BlockHeightTime - now)) * Params().TargetSpacing() +
   (BlockHeightTime - now) * nSlowInterval) / Params().AdjustmentInterval();

    // ahead by more than one interval;
    else if (now < BlockHeightTime) nIntervalDesired = nSlowInterval;
    
    // behind by more than an interval.
    else  nIntervalDesired = nFastInterval;
    
    // find out what average intervals over last 5, 7, 9, and 17 blocks have been.
    avgRecentTimestamps(pindexLast, &avgOf5, &avgOf7, &avgOf9, &avgOf17);    

    // check for emergency adjustments. These are to bring the diff up or down FAST when a burst miner or multipool
    // jumps on or off.  Once they kick in they can adjust difficulty very rapidly, and they can kick in very rapidly
    // after massive hash power jumps on or off.
    
    // Important note: This is a self-damping adjustment because 8/5 and 5/8 are closer to 1 than 3/2 and 2/3.  Do not
    // screw with the constants in a way that breaks this relationship.  Even though self-damping, it will usually
    // overshoot slightly. But normal adjustment will handle damping without getting back to emergency.
    toofast = (nIntervalDesired * 2) / 3;
    tooslow = (nIntervalDesired * 3) / 2;

    // both of these check the shortest interval to quickly stop when overshot.  Otherwise first is longer and second shorter.
    if (avgOf5 < toofast && avgOf9 < toofast && avgOf17 < toofast)
    {  //emergency adjustment, slow down (longer intervals because shorter blocks)
      LogPrintf("GetNextWorkRequired EMERGENCY RETARGET\n");
      difficultyfactor *= 8;
      difficultyfactor /= 5;
    }
    else if (avgOf5 > tooslow && avgOf7 > tooslow && avgOf9 > tooslow)
    {  //emergency adjustment, speed up (shorter intervals because longer blocks)
      LogPrintf("GetNextWorkRequired EMERGENCY RETARGET\n");
      difficultyfactor *= 5;
      difficultyfactor /= 8;
    }

    // If no emergency adjustment, check for normal adjustment.
    else if (((avgOf5 > nIntervalDesired || avgOf7 > nIntervalDesired) && avgOf9 > nIntervalDesired && avgOf17 > nIntervalDesired) ||
    ((avgOf5 < nIntervalDesired || avgOf7 < nIntervalDesired) && avgOf9 < nIntervalDesired && avgOf17 < nIntervalDesired))
    { // At least 3 averages too high or at least 3 too low, including the two longest. This will be executed 3/16 of
      // the time on the basis of random variation, even if the settings are perfect. It regulates one-sixth of the way
      // to the calculated point.
      LogPrintf("GetNextWorkRequired RETARGET\n");
      difficultyfactor *= (6 * nIntervalDesired);
      difficultyfactor /= (avgOf17 + 5 * nIntervalDesired));
    }

    // limit to doubling or halving.  There are no conditions where this will make a difference unless there is an
    // unsuspected bug in the above code.
    if (difficultyfactor > 20000) difficultyfactor = 20000;
    if (difficultyfactor < 5000) difficultyfactor = 5000;

    uint256 bnNew;
    uint256 bnOld;

    bnOld.SetCompact(pindexLast->nBits);

    if (difficultyfactor == 10000) // no adjustment.
      return(bnOld.GetCompact());

    bnNew = bnOld / difficultyfactor;
    bnNew *= 10000;

    if (bnNew > Params().ProofOfWorkLimit())
      bnNew = Params().ProofOfWorkLimit();

    LogPrintf("Actual time %d, Scheduled time for this block height = %d\n", now, BlockHeightTime );
    LogPrintf("Nominal block interval = %d, regulating on interval %d to get back to schedule.\n",
     Params().TargetSpacing(), nIntervalDesired );
    LogPrintf("Intervals of last 5/7/9/17 blocks = %d / %d / %d.\n",
     Params().TargetSpacing(), avgOf5, avgOf7, avgOf9, avgOf17);
    LogPrintf("Difficulty Before Adjustment: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("Difficulty After Adjustment:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

Nowi
Full Member
***
Offline Offline

Activity: 140
Merit: 100


View Profile
April 19, 2015, 08:20:56 AM
 #4

Really interisting. Thank you for this post  Roll Eyes

muddafudda
Legendary
*
Offline Offline

Activity: 980
Merit: 1003



View Profile
April 19, 2015, 11:47:44 AM
 #5

www.Howtocloneanaltcoin.com is better and windows users also covers more. Maybe not better but a slightly clearer format


            █ █ █ █ █
         ██           ██
       ██     █ █ █ █   ██
     ██    ██        ██
   ██   ██               
  ██   ██     ████████                  ██████████
            ███          ██   █████████     ██      ██████  ██   ███████  ██    ███   ███████
 ██   ██    ███              ██      ███    ██      ██          ███       ██   ███  ██
 ██   ██    ███  ██████  ██  ██      ███    ██      ██      ██  ███       ██  ███   ██
            ███      ██  ██  ██      ███    ██      ██      ██  ███       ██████     ███████
 ██   ██    ███      ██  ██  ██      ███    ██      ██      ██  ███       ██  ██           ██
             ██      ██  ██  ██      ███    ██      ██      ██  ███       ██   ███         ██
 ██   ██      ███████    ██   █████████     ██      ██      ██   ███████  ██    ███  ███████
  ██   ██                           ███
   ██    ██          ██            ███
     ██    ██ █ █ █ █   ██
       ██             ██
          █ █ █ █ █ █
























Telegram     Facebook     Twitter     Medium
-------------------------------------------------------------------
.WEBSITE. |█| .WHITEPAPER.












......BOUNTY......
-----------------------------------
..ANN THREAD..
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 19, 2015, 04:53:51 PM
 #6

Hmm, okay.  The list format with headers in bold is considered clearer?  I can do that, I guess.  Good reminder about what normal people like, though.  I always forget how visually oriented most people are; I live and breathe text and code and don't even notice visual details like that.  It's a communication problem, actually.  People present pictures thinking they're clearer, and to me they just aren't.  Important parts of the information are always missing from pictures.  At least I don't see them there.  Normal people think a map is clearer than written instructions, even when the map doesn't give the names of the darn streets!  So I get lost not knowing what streets to be looking for because the place never really looks like the map.  But enough about one of my personal issues.... 

It looks like he's got good expertise for doing it on Windows, which I have heard is tough.  He even uses the Windows command line fairly effectively, even though it looks like the Windows command line is still almost as crippled as I remember it being.  He couldn't even do a recursive string replacement from his command line, let alone changing filenames.  If you have to do it by hand like that, editing and renaming every file one at a time, you're going to make mistakes and miss stuff.  Scary.

Wait, it looks like he didn't rename files.  He's got an alt, and all the source files are still named bitcoin-whatever?  And he has to rename his executables every time after he builds?  Ergh.  That would bother me a lot more than it does him, I guess.  Is not being bothered by text inconsistencies like that another "normal people" thing? 

It does look like he's gotten a lot further with his guide than I have yet, covering topics like hosting and premine and retargeting and so on that I haven't touched yet.  So props to him for that.

I'm probably going to need someone with that kind of Windows expertise to port my stuff when I launch.  I haven't used Windows in a long time, and it would be hard for me to test a windows build even if I attempted to make one.  I'd probably have to rent a cloud server with Windows on it, then read a lot about how to configure a build environment on Windows, and start really from zero. 

Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 19, 2015, 05:36:22 PM
 #7

Do the edits make it clearer for normal people to read? 
muddafudda
Legendary
*
Offline Offline

Activity: 980
Merit: 1003



View Profile
April 20, 2015, 05:52:38 AM
 #8

Hmm, okay.  The list format with headers in bold is considered clearer?  I can do that, I guess.  Good reminder about what normal people like, though.  I always forget how visually oriented most people are; I live and breathe text and code and don't even notice visual details like that.  It's a communication problem, actually.  People present pictures thinking they're clearer, and to me they just aren't.  Important parts of the information are always missing from pictures.  At least I don't see them there.  Normal people think a map is clearer than written instructions, even when the map doesn't give the names of the darn streets!  So I get lost not knowing what streets to be looking for because the place never really looks like the map.  But enough about one of my personal issues....  

It looks like he's got good expertise for doing it on Windows, which I have heard is tough.  He even uses the Windows command line fairly effectively, even though it looks like the Windows command line is still almost as crippled as I remember it being.  He couldn't even do a recursive string replacement from his command line, let alone changing filenames.  If you have to do it by hand like that, editing and renaming every file one at a time, you're going to make mistakes and miss stuff.  Scary.

Wait, it looks like he didn't rename files.  He's got an alt, and all the source files are still named bitcoin-whatever?  And he has to rename his executables every time after he builds?  Ergh.  That would bother me a lot more than it does him, I guess.  Is not being bothered by text inconsistencies like that another "normal people" thing?  

It does look like he's gotten a lot further with his guide than I have yet, covering topics like hosting and premine and retargeting and so on that I haven't touched yet.  So props to him for that.

I'm probably going to need someone with that kind of Windows expertise to port my stuff when I launch.  I haven't used Windows in a long time, and it would be hard for me to test a windows build even if I attempted to make one.  I'd probably have to rent a cloud server with Windows on it, then read a lot about how to configure a build environment on Windows, and start really from zero.  



Two different guides. I'm pretty sure the name change is one of the first parts to the clone. Both are different and both cater for different needs. If you get stuck on something when you go through windows give me a yell. And yes it's missing the replacement of alert keys.


Question? Can I post you guide there?

Oh and the windows command line thing. I like to visually edit my code personally, this gives me a better understanding of what happening also around the code I am editing. Each to their own though.


            █ █ █ █ █
         ██           ██
       ██     █ █ █ █   ██
     ██    ██        ██
   ██   ██               
  ██   ██     ████████                  ██████████
            ███          ██   █████████     ██      ██████  ██   ███████  ██    ███   ███████
 ██   ██    ███              ██      ███    ██      ██          ███       ██   ███  ██
 ██   ██    ███  ██████  ██  ██      ███    ██      ██      ██  ███       ██  ███   ██
            ███      ██  ██  ██      ███    ██      ██      ██  ███       ██████     ███████
 ██   ██    ███      ██  ██  ██      ███    ██      ██      ██  ███       ██  ██           ██
             ██      ██  ██  ██      ███    ██      ██      ██  ███       ██   ███         ██
 ██   ██      ███████    ██   █████████     ██      ██      ██   ███████  ██    ███  ███████
  ██   ██                           ███
   ██    ██          ██            ███
     ██    ██ █ █ █ █   ██
       ██             ██
          █ █ █ █ █ █
























Telegram     Facebook     Twitter     Medium
-------------------------------------------------------------------
.WEBSITE. |█| .WHITEPAPER.












......BOUNTY......
-----------------------------------
..ANN THREAD..
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 20, 2015, 06:27:43 AM
 #9


Two different guides. I'm pretty sure the name change is one of the first parts to the clone. Both are different and both cater for different needs. If you get stuck on something when you go through windows give me a yell.

Thank you for that.  And I'm likely to take you up on it when I think I've got stuff ready.  Recent versions of Windows are completely a mystery to me, and I wouldn't know where to start. 

Question? Can I post you guide there?

Sure.  I haven't made the new edits on my blog post yet, but please include a link back to it.

Oh and the windows command line thing. I like to visually edit my code personally, this gives me a better understanding of what happening also around the code I am editing. Each to their own though.

Sure, I understand that.  When I'm getting ready to support a codebase, I spend hours a day just READING the code to try to understand all the parts and how they work together.  So I completely understand the need to see it and get familiar with it and see how everything interacts.  The name change though, is total and unambiguous, so it can really be done in one step and doing it otherwise I'd be afraid of missing stuff or making mistakes. 

I know Windows works really well for a lot of people, but all I really remember about it is being frustrated whenever I tried to do anything complicated from the command line.  It has environment variables, some filename globbing and you can use pipes to send output to files or devices or the next command, so the command line isn't overtly broken.  But recursive utilities, stream editors, patterned renaming, anything like the find command...  I never discovered any way to do those things. I don't know if that's because I just am ignorant about tools and utilities available on Windows, or if those tools and utilities really don't exist.  Anyway, I don't mean to insult it - I just don't know how people do the tasks that make me reach for those utilities. 

I guess I'm writing this guide aimed at Unix/Linux users because I don't even know HOW to do most of this stuff on Windows.

Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 20, 2015, 07:15:09 PM
 #10


Sure.  I haven't made the new edits on my blog post yet, but please include a link back to it.


Okay, I've got the new edits in the blog post now.  So linking to it will get you a better version. 
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 21, 2015, 12:55:24 AM
 #11

Bump.  I edited the post adding code for the MIDAS difficulty adjustment system. 
TheMystic
Member
**
Offline Offline

Activity: 171
Merit: 10


View Profile
April 21, 2015, 08:01:30 PM
 #12

This is a fascinating thread. Thanks for the info.

► ClipX ◄ ♦ The World’s first Blockchain E-Learning Platform ♦ ► ClipX ◄
───●♦●───●♦●───●♦●───●♦●───●♦●─[   Bounty Detective   ]─●♦●───●♦●───●♦●───●♦●───●♦●───
Website◂ | ▸Twitter◂ | ▸Instagram◂ | ▸Facebook◂ | ▸Telegram◂ | ▸LinkedIn◂ | ▸Youtube◂ | ▸Whitepaper
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 22, 2015, 02:50:01 AM
 #13

Bump.  I've updated the article above on Difficulty Adjustment, and also posted it to a blog so now there's a link to the online article.
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
April 23, 2015, 03:52:35 AM
Last edit: April 23, 2015, 07:29:48 PM by Cryddit
 #14

Okay, this time I'm going to talk about how to claim the coinbase transaction from the genesis block.  Those who want to stick a premine into the genesis block should be paying attention here.


Get the private key for the coinbase
Earlier, we used openssl to get a key pair to use for the genesis coinbase.  We pasted the public key, in hex form, into the coinbase transaction of the genesis block.   Under normal circumstances this coinbase is not spendable. Because there is no wallet at the time the coinbase transaction is created, the private key does not get saved into a wallet.  But if we can import the private key into our wallet after the wallet is created, then the genesis coinbase can be spent.

So, go back to the key pair whose public key you used for the genesis coinbase.  The corresponding private key is the one you need to spend it.  But first you have to figure out what the heck it looks like in the base58 format that you can import into your wallet.

So you need to take the private key and do things to it, to get it into wallet-importable format.  

Here is the sequence of steps you need to do:  

First, take your private key:  For this example, let's say it's
Code:
0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
(which it certainly won't be, but I digress.)

Add the prefix byte for newcoin's secret keys.
Then, whatever byte you picked as the value for base58prefixes[SECRET_KEY] above, paste that byte in (in hex form!) as a prefix to the key.  We'll say our byte for base58prefixes was 0xAA.

So now you've got
Code:
AA0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

Find SHA256D of the result

Now you take double SHA256 of that, which you can do from the command line again.
Code:
echo AA0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF | xxd -r -p > temp
puts the key in binary form into the file temp.
Code:
openssl dgst -sha256 temp
outputs the SHA256 hash of that key.  It will look like this:
Code:
SHA256(temp)= 855d46b953763179ae26937d7d5d9a7fbdf063f6e23fa5abc08e02b1ee202b0e
Now you copy the hex string and paste it into the following command:
Code:
echo 855d46b953763179ae26937d7d5d9a7fbdf063f6e23fa5abc08e02b1ee202b0e | xxd -r -p > temp2
The effect of that is to put the hash of the key, in binary form into the file temp2.  So now you can get SHA256 of the hash like so:
Code:
openssl dgst -sha256 temp2
and openssl will spit out the hash of the hash.  

The effect is to do 2 iterations of SHA256 on the private key:  Without piping through xxd both times, we'd be doing SHA256 on a string of bytes which happens to be the ASCII representation of the hexadecimal string instead.  Anyway, the output from that is the  SHA256D hash of the prefix byte plus private key.  For our example, it happens to be
Code:
SHA256(temp2)=02709d7a22eebf159eb9e67669afb4c565a6fa90d9ac2f6069beccce226b04ab

Extract the checksum bytes from the SHA256D hash
The first four bytes of that - which are 02, 70, 9d, 7a, are the checksum for the private key - this is a four-byte code that is appended to keys to make it extremely unlikely (about one chance in four billion) that a mistyped key will actually be a valid key.  This is intended to make it unlikely that people spend coins to wrong addresses.  Of course they do that anyway, but thanks to this checksum it's not because they mistype the addresses.


Append the Checksum bytes to the prefix-extended key
Anyway, you take the key, with the prefix byte, and put the checksum bits at the end of it, so you get
Code:
AA0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF02709D7A.

Now, this is a number in hexadecimal, which you have to convert into base58check form.  https://en.bitcoin.it/wiki/Base58Check_encoding  on the bitcoin wiki explains how base58check is encoded, but doesn't point at any handy utility to actually do it that doesn't depend on bitcoin's secret-key prefix.  So I'm going to code one.

A simple little lisp dialect called Scheme, believe it or not, is my favorite scripting language.  I have mit-scheme on my machine, and Scheme has standard bignums and understands numeric notation in hexadecimal.  If you're happier doing this sort of thing in Haskell or Eiffel or Python or whatever, use that instead.  But I'll actually write the six-line program for you if you want to use Scheme.  If you don't have it on your system, you can type

Code:
sudo apt-get install mit-scheme
to get it. Then at the command line type
Code:
mit-scheme

to start it, and paste this function definition into it:

Code:
(define (base58check input)
   (define (base58digit k) (string-ref "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" k))
   (define (extractdigits n digits)
       (if (> 58 n)
         (list->string (cons (base58digit n) digits))
  (extractdigits (quotient n 58) (cons (base58digit (modulo n 58)) digits))))
   (extractdigits input '()))

Now you just have to give your key to that function as a hexadecimal number:

Code:
(base58check #xAA0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF02709D7A)

and mit-scheme will politely cough out the base58check form of it;  In our example, this is the string

Code:
"6hU445Fi7j2WSwc2uLsbcQMJ1r2xbENWxGdfxTApKaRRaQ2Ppk1"

And that is the form of the key that you need to import into your wallet, to enable you to spend the coinbase transaction from the genesis block.

Cool, huh?  Now type
Code:
(exit)
and then 'y' at the yes/no prompt, to quit scheme.

Adding a Premine

Now we're going to come to one of the most abused features of cryptocurrency; I'm going to explain how to add a premine.  

The next thing, if you want to treat the genesis coinbase as your premine, is the question, how to change the amount?  There are three things you have to change.  The obvious thing is in chainparams.cpp,  in the line above the one where you pasted in the coinbase tx public key.  It's at the line where the code says

Code:
txNew.vout[0].nValue = 50 * COIN;

So, we'll say you want 5000 coins instead of 50 for your premine.  That's an easy enough change here; you just change the number here so it says
Code:
txNew.vout[0].nValue = 5000 * COIN;
instead.  

Change GetBlockValue to Allow your Premine
But this is only the obvious thing.  There are two other things you have to change for this to work.  The next one is the function GetBlockValue in main.cpp.  If you don't change this, your block chain will not be valid when your client tries to check it. This function says what the coinbases are supposed to be worth, and if the client checking the block chain finds a coinbase transaction that doesn't match what this function says it ought to be, then it will reject the genesis block.  The function looks like

Code:
CAmount GetBlockValue(int nHeight, const CAmount& nFees)
{
    CAmount nSubsidy = 50 * COIN;
    int halvings = nHeight / Params().SubsidyHalvingInterval();

    // Force block reward to zero when right shift is undefined.
    if (halvings >= 64)
        return nFees;

    // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
    nSubsidy >>= halvings;

    return nSubsidy + nFees;
}

and you want to make the subsidy for the block at height zero (ie, the genesis block) worth 5000 coins instead of 50.  And while we're here we might as well correct the comment's assumption of ten-minute blocks.  So your revised function can look like this:

Code:
CAmount GetBlockValue(int nHeight, const CAmount& nFees)
{
    CAmount nSubsidy = (nHeight == 0 ? 5000 : 50) * COIN;
    int halvings = nHeight / Params().SubsidyHalvingInterval();

    // Force block reward to zero when right shift is undefined.
    if (halvings >= 64)
        return nFees;

    // Subsidy is cut in half every 350,000 blocks which will occur approximately every 4 years.
    nSubsidy >>= halvings;

    return nSubsidy + nFees;
}

Then go back to chainparams.cpp  and set the subsidy halving interval to 350000 instead of 210000 to maintain the 4-year halving interval (assuming you want a 4-year halving interval).  Another effect of this change is that it will also change your ultimate number of coins to be issued to be ~35M instead of ~21M.  

Regenerate the Nonces

Okay, that was the second of three things.  Now for the third.  You should already know what this is.  When we changed the genesis coinbase,  We changed the hash of the transaction.  And when we changed the hash of the transaction, we changed the merkle root in the genesis block.  And that invalidated our nonce.  So you need to mine your genesis blocks again.  

I covered this already when I explained how to mine genesis blocks.  You go back to chainparams.cpp, change the 'false's to 'true's, erase the ~/.newcoin directory, compile, and start it up.  It'll take a while.  Then you look at the debug.log in the (re-created) ~/.newcoin directory to get the new values.  Paste them in for the main params, Rinse, repeat, paste in the testnet params.  Rinse, repeat, paste in the regtest params.  Then change the 'true's to 'false's, and compile again.

So now newcoin has a genesis block coinbase with a premine of 5000 coins, and you have a key you can import into your wallet later which will allow you to actually spend the 5000 coins.

Changing the number of coins that can be issued

With your premine and different halving interval you've changed the number of coins that can be issued.  But you need to change other parts of the code for this to be fully supported.  The first and most obvious is in amount.h, where it says
Code:
/** No amount larger than this (in satoshi) is valid  */
static const CAmount MAX_MONEY = 21000000 * COIN;
And, obviously, you change the 21000000 to 35004950.  (remember, you added 4950 coins to the total when you changed the output of the genesis coinbase).


The second is in rpcserver.cpp, in the function AmountFromValue. It looks like this:  
Code:
CAmount AmountFromValue(const Value& value)
{
    double dAmount = value.get_real();
    if (dAmount <= 0.0 || dAmount > 21000000.0)
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
    CAmount nAmount = roundint64(dAmount * COIN);
    if (!MoneyRange(nAmount))
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
    return nAmount;
}
And once again, you need to change that 21000000 to 35004950.  And now you have code for a client that is correct for your new block spacing and coin distribution.  

frooble
Newbie
*
Offline Offline

Activity: 2
Merit: 0


View Profile
May 27, 2015, 06:20:54 PM
 #15


Mine the genesis block and insert the new values
Got all that? Now run newcoin-qt.

It will throw up a dialog box asking where to install. Let it have the default it wants, which will be a new subdirectory of your home directory named ~/.newcoin.

Then Nothing will happen.  For twenty minutes to an hour, usually.  Maybe more than an hour, depending on dumb luck and the speed of your computer.  If your computer’s slow, this may be a good time to go get a sandwich.

Here's what's actually happening.  It set the nonce, hashed the genesis block, noticed it didn’t match 0x01, and is now living in that tight little empty for loop, incrementing the hash, hashing the block, and checking to see whether the new hash is low enough to meet proof-of-work requirements.

After a while, it will die. Meaning, it found a nonce that gave the genesis block a hash low enough to pass proof-of-work, got out of the for loop, logged the new hash and nonce and the Merkle tree value, and then hit the assert that still insists on the hash value being Bitcoin’s genesis block hash value. So you want to see the new values. Type

tail ~/.newcoin/debug.log

and you’ll see the last few lines of logfile output.



When I run newcoin-qt, the dialog box does not come up ... instead the code goes immediately into code where the loop to generate the genesis hash
Code:
for(genesis.nNonce == 0; genesis.GetHash() > bnProofOfWorkLimit; genesis.nNonce++){ }
so no debug.log gets created and there is nothing to inspect afterwards.

What happened here?
Cryddit
Legendary
*
Offline Offline

Activity: 924
Merit: 1055


View Profile
May 28, 2015, 02:54:54 AM
 #16

Huh 

I don't know.  If the directory already existed, it wouldn't throw the dialog box.  So  first do a sanity check and type

cd ~/.newcoin

to see if the directory exists. 

If it does, your values will be in the last dozen lines of debug.log in that directory.

If it doesn't, then check ~/.bitcoin instead to see if you missed the file directory name when you were changing "bitcoins" to "newcoins."

frooble
Newbie
*
Offline Offline

Activity: 2
Merit: 0


View Profile
May 29, 2015, 12:34:09 PM
 #17

I have neither ~/.newcoin no ~/.bitcoin directories available

I see the issue.
The code is creating (in chainparams.cpp) static instances of CMainParams CTestNetParams CRegTestParams (and CUnitTestParams for that matter) .. so the hashing code is getting executed before program main() is  invoked.

So I am not sure what you did to bypass that static instantiation to get the dialog box to come up.

I will put some std:cout calls to write to console and grab the initial hash values to replace in the code ...

Will that work as well ? Or will something not get created ( in ~/.newcoin) that needs to get created
defaced
Legendary
*
Offline Offline

Activity: 2100
Merit: 1011


Franko is Freedom


View Profile WWW
May 30, 2015, 12:39:11 AM
 #18

cool guide, there is an even easier way to mine a genesis block

https://github.com/lhartikk/GenesisH0

Fortune Favors the Brave
Borderless CharityEXPANSEEXRAllergy FinderFranko Is Freedom
john75077
Newbie
*
Offline Offline

Activity: 26
Merit: 0


View Profile WWW
August 14, 2015, 04:34:39 PM
 #19

Can this be compiled on Debian 8?
zero01
Member
**
Offline Offline

Activity: 98
Merit: 10


View Profile
August 14, 2015, 05:01:40 PM
 #20

very attractive, but none that I know, maybe I could just use  Grin
Pages: [1] 2 3 4 »  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!