By Niren Shah
Blockchains !!! How about that for starters? If you have been living under a rock, see the wiki. While that may the hottest buzzword in the tech space these days, the concept is fairly simple. The basic idea is as follows:
Here is probably the most trivial (and incomplete :) ) implementation of the concepts in less than 50 lines of code. Have fun!
Blocks
Blocks are super trivial. They consist of:
That's literally it. You can see that in the code below. In addition to that, we have a few helper functions:
Mining requires a little more explanation. The idea for "mining" is to create hashes but in a way that isn't trivial and also in a way that can be made more difficult over time. Normally, it is extremely fast to create a hash of a little bit of data. This means that if someone wanted to manipulate the data in the blocks -- they could do so and rewrite the entire chain quickly. In order to prevent this, the calculation of the hash for each block is made more difficult than the previous one. With this in place, you'd need immense computing power to "hack" a chain. And since mining is a collaborative exercise and these chains are distributed, you'd need more computing power than the collective power of all the people mining the blocks. This makes it almost impossible.
Here we simply say that for difficulty level 4, we need the hash to start with 4 zeroes. For difficulty level 5, starts with 5 zeroes and so on. Play around with the code and you'll see how quickly it gets to be a lot more work. We just tweak the nonce value to create a different hash if the generated one doesn't meet the difficulty criteria.
Blockchains
Blockchains are nothing more than a collection of these blocks in generated order. In the code below, we simply use a List to store them along with a couple of helper functions:
There isn't anything fancy going on here at all.
Runner
The runner is just a Java Main to create a new blockchain and add a couple of blocks to it and then validate the chain. It also prints out the chain at various points so that you can see what is going on. Here's the output:
Adding block 1
{hash: 0000D189CA96E685ED82D895EEF482AE939FC39D807602B15F1FD7BFFEF95B1B, previousBlockHash: null, nonce: 11634, data: Hello, World!}
Adding block 2
{hash: 0000D189CA96E685ED82D895EEF482AE939FC39D807602B15F1FD7BFFEF95B1B, previousBlockHash: null, nonce: 11634, data: Hello, World!}
{hash: 0000EE32F1B6F5BA78F148CD7B85C12F1A808FD80D514C6C99EA3889B5026E07, previousBlockHash: 0000D189CA96E685ED82D895EEF482AE939FC39D807602B15F1FD7BFFEF95B1B, nonce: 9744, data: Hello, Blockchain!}
Is chain valid?: true
Have fun mining :)
Block.java
package com.amolsolutions.blockchain;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.DatatypeConverter;
public class Block {
public String hash;
public String previousBlockHash;
private String data;
private int nonce = -1;
public Block(String data) {
this.data = data;
}
public String toHash() { //calculate the SHA-256 hash for the relevant pieces
String retval = "";
try {
MessageDigest alg = MessageDigest.getInstance("SHA-256");
StringBuffer hashData = new StringBuffer().append(previousBlockHash).append(data).append(nonce);
retval = DatatypeConverter.printHexBinary(alg.digest(hashData.toString().getBytes("UTF-8")));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
//TODO: :)
}
return retval;
}
public void mine(int difficulty) { //recalculate hashes till the difficulty level is achieved
do {
nonce++;
hash = toHash();
} while(!hash.matches(String.format("^0{%d}.*",difficulty)));
}
@Override
public String toString() {
return String.format("{hash: %s, previousBlockHash: %s, nonce: %d, data: %s}", hash, previousBlockHash, nonce, data);
}
}
BlockChain.java
package com.amolsolutions.blockchain;
import java.util.ArrayList;
import java.util.List;
public class BlockChain {
private List<Block> chain = new ArrayList<Block>();
public Block addBlock(Block block) {
if(chain.size() > 0) { //add the previous block's hash if needed
block.previousBlockHash = chain.get(chain.size()-1).hash;
}
chain.add(block);
return block;
}
public void print() {
for (Block b : chain) {
System.out.println(b);
}
}
public boolean isValid() { //current and previous blocks' hash should match for the entire chain
for(int i = 0; i < chain.size(); i++) {
Block current = chain.get(i);
if(!current.toHash().equals(current.hash)) {
return false;
}
if(current.previousBlockHash != null) {
Block previous = chain.get(i-1);
if (!previous.toHash().equals(current.previousBlockHash)) {
return false;
}
}
}
return true;
}
}
Runner.java
package com.amolsolutions.blockchain;
public class Runner {
public static void main(String[] args) {
int difficulty = 4; //set the mining difficulty
BlockChain c1 = new BlockChain();
System.out.println("Adding block 1");
c1.addBlock(new Block("Hello, World!")).mine(difficulty);
c1.print();
System.out.println("Adding block 2");
c1.addBlock(new Block("Hello, Blockchain!")).mine(difficulty);
c1.print();
System.out.println("Is chain valid?: " + c1.isValid());
}
}