Blockchain explained by simple Java code

Tom Nguyen
Apr 11, 2018 · 5 min read

Following my problem with KFC system, let’s see another real world problem: The food shop chain with a central hotline/database couldn’t work sometimes because of single point that needs to be always up. If the order database could be distributed, the high availability of the system could be increased. It’s when blockchain shows its value by all distributed shops store the copy of single order database.

Blockchain is combination of block and chain. Block is unique and stores the data/information, chain stores a sequence of blocks that each block points to the previous one.

This article describes the simple blockchain that’s used to store the orders of all food shops in the system.

Let’s start with Block with a simple version of Order.

public class Block {
public String hash;
public String previousHash;
public Order order;
public long timeStamp;

public Block(Order order, String previousHash) {
this.order = order;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();

this.hash = Generator.generateHash(
this.previousHash
+ this.timeStamp
+ this.order.toString());
}

public static Block getGenesisBlock() {
Order order = new Order("Its me", "Nothing", 0);
Block block = new Block(order, "");
block.timeStamp = 0;
block.hash = Generator.generateHash(
block.previousHash
+ block.timeStamp
+ block.order.toString());
return block;
}
}

One Block has the unique ID, called hash, with time the block is generated, called timeStamp, and hash of the previous block, called previousHash. Block has order that store the food order data.

The first block that doesn’t have previous one, called genesis block, should be hard-coded.

A BlockChain has a list of block with some add-in methods like validateBlock() or validate() the block chain.

public class BlockChain implements Cloneable {
private final ArrayList<Block> chain;

public BlockChain() {
this.chain = new ArrayList<>();
this.chain.add(Block.getGenesisBlock());
}

public ArrayList<Block> getBlocks() {
return (ArrayList<Block>) chain.clone();
}

public long size() {
return chain.size();
}

public void add(Block block) {
if (validateBlock(chain.get(chain.size() - 1), block)) {
chain.add(block);
} else {
throw new IllegalArgumentException("Invalid block");
}
}

public String getLastHash() {
return this.chain.get(this.chain.size() - 1).hash;
}

public boolean validateBlock(Block previousBlock, Block block) {
return block.previousHash.equals(previousBlock.hash);
}

public boolean validate() {
ArrayList<Block> subChain = (ArrayList<Block>) chain.subList(1, chain.size() - 1);
Block previousBlock = chain.get(0);

for (Block currentBlock : subChain) {
if (!validateBlock(previousBlock, currentBlock)) {
return false;
}
previousBlock = currentBlock;
}

return true;
}

@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

The reason of class BlockChain implementing interface Cloneable should be describe later.

Now each food shop, called Node, has a single blockchain. To make sure all nodes store the same blockchain, we must firstly make sure all nodes can ‘know’ others. Following:

  • If the node is started without connectedNode, it’s the first node
  • If the node is started with connectedNode, it asks the connectedNode for the list of nodes in the network, calling to getNodes(). Then the node tells those existing nodes that it wants to connect to the network, calling to registerToNetwork()
public class Node {
public String address;

protected BlockChain blockChain;
private ArrayList<Node> nodes;

public Node(String address, Node connectedNode) {
this.address = address;
blockChain = new BlockChain();

if (connectedNode != null) {
registerToNetwork(connectedNode);
try {
getBlockChain(connectedNode);
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
nodes = new ArrayList<>();
}
}

public void add(Block block) {
try {
this.blockChain.add(block);
} catch (IllegalArgumentException e) {
if (this.nodes.size() > 0) {
try {
getBlockChain(this.nodes.get(0));
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}

public void mine(Block block) {
this.blockChain.add(block);
this.nodes.forEach((node) -> {
node.add(block);
});
}

private void registerToNetwork(Node connectedNode) {
this.nodes = connectedNode.getNodes();
this.nodes.add(connectedNode);
this.nodes.forEach((node) -> {
node.register(this);
});
}

private void getBlockChain(Node connectedNode) throws CloneNotSupportedException {
this.blockChain = (BlockChain) connectedNode.blockChain.clone();
}

public ArrayList<Node> getNodes() {
return (ArrayList<Node>) this.nodes.clone();
}

public void register(Node node) {
this.nodes.add(node);
}
}

To make sure blockchain consistently, when a node mines a block, it needs to notify all nodes in the network by method mine(). In this problem, it means a food shop creates order for a customer.

It is. A blockchain is ready. Class Store and FoodBlockChainTest are for testing: it creates 3 stores (kfc, burger, pho) and registers them to the network, each store simulates creating the orders and add them to blockchain. You should see the result in your console. This example is just simulated by distributing the system in threads, that’s why I used Cloneable to get it looked like ‘distributed’ without references. In the real blockchain, methods like getNodes(), getBlockChain(), register()… should be called by REST or RPC.. and each node has it owned isolated data. But networking isn’t our focus here, you can easily write some extra code.

public class Store extends Node implements Runnable {

public Store(String address, Node connectedNode) {
super(address, connectedNode);
}

public void testOrders() throws InterruptedException {
String[] customerName = {"Messi", "Ronaldo", "Pogba"};
String[] orderDetails = {"KFC", "Burger", "Wine" };
Random random = new Random();

for (int i = 0; i < 3; i++) {
Block block = new Block(
new Order(customerName[random.nextInt(3)], orderDetails[random.nextInt(3)], random.nextInt(50)),
this.blockChain.getLastHash()
);
try {
this.mine(block);
System.out.println(String.format("%s mined: %s", address, block.hash));
} catch (IllegalArgumentException ex) {
System.out.println(String.format("%s mined invalid block: %s", address, block.hash));
}
Thread.sleep(random.nextInt(3) * 1000 + 100);
}
}

public void printBlockChain() {
System.out.println("------ Block chain of [" + address + "] ------");

this.blockChain.getBlocks().forEach(block -> {
System.out.println(block.hash);
});

System.out.println("------ END ------");
}

@Override
public void run() {
try {
testOrders();
} catch (InterruptedException ex) {
Logger.getLogger(Store.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class FoodBlockChainTest {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Store kfc = new Store("KFC Vietnam", null);
Store burger = new Store("Burger King", kfc);
Store pho = new Store("Pho", kfc);

Store[] stores = {kfc, burger, pho};

for (Store store : stores) {
Thread thread = new Thread(store);
thread.start();
}

try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(FoodBlockChainTest.class.getName()).log(Level.SEVERE, null, ex);
}

for (Store store : stores) {
System.out.println("");
store.printBlockChain();
}
}
}

It’s of course not a real blockchain that you can use now. There are many things that this article didn’t mention: chain conflict, Proof of Work, sub chain, confirmation… But I hope you can get the idea of blockchain and its value through a simple code. It just a start, I will get back with another topic later.

Full code should be found here: https://github.com/hiennvn/simple-blockchain-java

Zen8Labs

Zen8Labs engineering blogs

    Tom Nguyen

    Written by

    Software Engineer

    Zen8Labs

    Zen8Labs

    Zen8Labs engineering blogs

    More From Medium

    Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
    Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
    Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade