Develop your first application on Blockchain

Blockchain !! No matter where you go, the tech circles and media houses are agog with stories about how Blockchain technology will have a profound impact on different aspects of mankind — how businesses will be run more transparently and with lesser number of intermediaries and so on and so forth. But hey, as a developer, all you care about is to find out how to build real-life applications using Blockchain technology !! As I started learning Blockchain myself few months ago, I found information in bits and pieces scattered all over Internet. In this article, I shall try to cover as many aspects of Blockchain development as possible, so that you don’t have to run around like I did.

What do you want to build?

So, what we are going to do is pick up a business use case where (we think) Blockchain can be used and then see what does it take to build a simple application that uses Blockchain. For example, take the Automobile industry and notice how people go through agonising moments while buying a used car. Are there any hidden problems in the car? Is it a salvage title? Did the previous buyer perform regular maintenance at authorised service stations? Nowadays, cars come fitted with connected devices, transmitting all kinds of information about performance, mileage, service record, repair etc. Imagine how much beneficial it would have been if we could store such information in a World Wide Ledger that is accessible to everyone. And since this data is immutable, no one would be able to tamper it in any shape or form. Therefore, let’s build an application that stores and retrieves car data in a Blockchain over its entire life cycle. To make things a little more interesting, we would like the application be smart enough to raise claims with Insurance provider if a car meets with an accident.

Let’s setup the Development Environment

Today, we will use Ethereum, one of the most popular frameworks, as the underlying Blockchain platform and Web3j as the Java library for integration with Ethereum nodes. If you are not familiar with Ethereum, you can read about it here. In order to understand how private Ethereum Blockchain networks are created and challenges encountered while using them, we will not use the Testnet network of Ethereum during our development. Instead, we will setup our own private Blockchain network, comprising of two Ethereum nodes. Our first node (Node#1) will be a miner and the second node (Node#2) will be used to submit transactions to Blockchain. I recommend you use two separate physical machines as nodes to understand how nodes connect with each other; however, you can also use two Docker instances on a single host. On each node, we will run Geth (implemented in Go language) as the Ethereum client, so, go ahead and install Geth on both Node#1 and Node#2.

Initialise your Blockchain

As you know, a Blockchain is a chain of Blocks wherein each Block stores a set of transactions and is also linked to its previous Block. You might be wondering how the first Block is created. That’s where initialisation of Blockchain comes into play where you provide details about the first Block, called Genesis Block. So, go to Node#1 and create a JSON file called “CustomGenesis.json” with the following content.

{
“config”: {
“chainId”: 1999,
“homesteadBlock”: 0,
“eip155Block”: 0,
“eip158Block”: 0
},
“nonce”: “0x0000000000000042”, “timestamp”: “0x0”,
“parentHash”: “0x0000000000000000000000000000000000000000000000000000000000000000”,
“gasLimit”: “0x8000000”, “difficulty”: “0x400”,
“mixhash”: “0x0000000000000000000000000000000000000000000000000000000000000000”,
“coinbase”: “0x3333333333333333333333333333333333333333”, “alloc”: {}
}

If you don’t understand what these parameters mean, don’t worry. For now, it will suffice to note the following:

  • chainId indicates the network Id of our private Blockchain network. All nodes of our network must have same chainId
  • difficulty indicates the amount of calculation our miner has to perform in order to create a valid Block. Since ours is a private network, we will keep it at a very low level so that transactions are executed faster by the miner.
  • gaslimit is the maximum amount of gas that can be spent per Block. The more the data in a transaction, the higher the gas limit should be set. Or, for a given gas limit, we can store lesser number of transactions in a Block, if the data in a single transaction increases. Again, since ours is a private network, we don’t want any such limit on transaction data, so will set the gas limit to very high value.

On my Windows laptop (Node#1), I have created a folder called ethereum under D: drive and kept the above CustomGenesis.json file over there. In case you are using a Linux box, create corresponding folder accordingly.

Next, create a data directory in Node#1 where all the Blockchain data will be stored. In my case, it is called blockdata inside D:\ethereum folder. Now, go to D:\ethereum and run the following command.

geth --datadir “D:\ethereum\blockdata” init CustomGenesis.json

You will see log messages in the console indicating the genesis Block has been written successfully. You will also see a Warning message that No etherbase has been set and no accounts found as default. Ignore it. Press Control-C and shutdown the Geth node. Node#1 is now setup successfully.

Go to Node#2 and repeat the same steps as above. Now, both the nodes have been initialised.

Create miner account

In Ethereum, every transaction must have an associated sender account that not only signs the transaction but must also have sufficient balance to pay the gas for the transaction. In our use case, since we don’t intend to transfer value between accounts, we just need to create an account that will be used to sign the transactions. The same account will also be used during the mining process, so that it gets ethers as rewards. So, let’s create an account in Node#1 (miner node) (don’t forget the password — ever !!).

geth --datadir "D:\ethereum\blockdata" account new

Run your Blockchain network

We are almost there. All we have to do now is start Geth on miner node (Node#1), do some mining (so that our Account has some ether), start Geth on Node#2 and then join Node#2 as a peer to Node#1. Here are the commands.

Go to Node#1 and run

geth --identity “miner” --rpc --rpcport “8042” --rpccorsdomain “*” --datadir “D:\ethereum\blockdata” --port “30303” --rpcapi “personal,db,eth,net,web3” --networkid 1999

It will start the Geth node with NetworkId as 1999, will receive HTTP-RPC calls at port# 8042 and will also listen for peer nodes at port# 30303.

Next, open another console window on Node#1 and run

geth attach

It will attach to a running Geth instance on local machine. In the command prompt, type

admin

Note down the enode value under nodeInfo attribute. You will need this while connecting Node#2 as a peer.

Now, go to Node#2 and run

geth --identity "node2" --rpcaddr "IP Address of Node#2" --rpc --rpcport "8042" --rpccorsdomain "*" --datadir "D:\ethereum\blockdata" --port "30303" --rpcapi "personal,db,eth,net,web3" --networkid 1999

Then, run

geth attach

Finally, on command prompt of Geth console, type

admin.addPeer("enode value of Node#1@IP Address of Node#1:30303")

It will look something like “enode://4ff89a043…..@10.11.202.11:30303”. Next, type

admin.peers 

If it prints details about peer nodes, including network attribute that shows IP Addresses of Node#1 and Node#2, then, you know that these two nodes have connected together. Node#2 will start downloading Blocks that have been mined so far by Node#1. If you don’t see any peer node, it could be due to Node#1 and Node#2 being unable to reach each other. Try Telnet from Node#2 to Node#1. The other possible reason could be incorrect NetworkId — both Nodes must have same NetworkId.

Instead of adding a peer from Geth command prompt every time, you can use static node JSON config file for automatic addition of peers. Check the Ethereum documentation for details. You can also use bootnodes argument while starting Geth instance on Node#2 but it does not seem to work always in case of private networks.

You are now all set !!! Yay !!

Let’s write the Smart Contract

Now that your private Blockchain network is up and running, let’s focus on writing the Smart Contract that manages car data. Remember what we had set out to achieve? To store and retrieve car events in Blockchain as and when they occur. Here is a simple Smart Contract, written in Solidity language, the most popular of all languages in which you can write Smart Contracts. If you are not familiar with Solidity, do read here.

Save this in a file, named VehicleStateContract.sol

pragma solidity ^0.4.9;
contract VehicleStateContract {
struct VehicleEvent {
string date;
int eventType;
string eventdescription;
string odometerreading;
string location;
}

struct VehicleDetails {
string vin;
string make;
string model;
string yearofmanuf;
string odometerreading;
string ownerType;
string description;
string fuelType;
}

mapping (string => VehicleEvent) private vehicle_events;

mapping (string => VehicleDetails) private vehicle_details;

string[] vins;

function getCountofVins() public constant returns (uint) {
return vins.length;
}

function getVinByIndex(uint index) public constant returns (string) {
if (vins.length > index) {
return vins[index];
}
else {
return "";
}
}

int constant STATE_ACCIDENT = 5;

address private owner;

function VehicleStateContract() {
owner = msg.sender;
}

event vehicleAccident(string vin);

event vehicleEvent(string vin, string date, int eventType, string eventdescription, string odometerreading, string location);

function vehicleProvision(string vin, string make, string model, string year, string odo, string vehowner, string desc, string fuel) {
vehicle_details[vin] = VehicleDetails(vin, make, model, year, odo, vehowner, desc, fuel);
vehicle_events[vin] = VehicleEvent(year, 1, 'Vehicle Provisioned', odo, 'Factory');
vins.push(vin);
}

function getVehicleDetails_part1(string vin) constant public returns (string, string, string) {
return (vehicle_details[vin].make, vehicle_details[vin].model, vehicle_details[vin].yearofmanuf);
}

function getVehicleDetails_part2(string vin) constant public returns (string, string, string, string) {
return (vehicle_details[vin].odometerreading, vehicle_details[vin].ownerType, vehicle_details[vin].description, vehicle_details[vin].fuelType);
}

function getVehicleEvent(string vin) constant public returns (string, int, string, string, string) {
return (vehicle_events[vin].date, vehicle_events[vin].eventType, vehicle_events[vin].eventdescription, vehicle_events[vin].odometerreading, vehicle_events[vin].location);
}

function vehicleUpdate(string vin, string date, int eventType, string eventdescription, string odometerreading, string location) {
vehicle_events[vin] = VehicleEvent(date, eventType, eventdescription, odometerreading, location);
if (eventType == STATE_ACCIDENT) {
vehicleAccident(vin);
}
vehicleEvent(vin, date, eventType, eventdescription, odometerreading, location);
}

function kill() {
if (owner == msg.sender) suicide (owner);
}
}

First, some thought-process on what we want to do inside Smart Contract. We want to store the details of every car registered with us inside our Smart Contract. However, for a given car, we don’t want to store all of its historical events inside Smart Contract since that would be too costly. Instead, we want to store the latest event of a car inside Smart Contract while use Blockchain logs (or events) for storing all historical events of the car. You can read this nice article about Ethereum Events and logs here. To be precise, by car events, we mean anything that happens to a car. For example, a car servicing is a car event, a car accident is another car event etc. For each of these, we would like to generate a log or event inside Ethereum Blockchain.

Now, let’s go through the Smart Contract step-by-step.

The first two sections define the structures of VehicleEvent and VehicleDetails. When a car event occurs, we will capture the car event type (Service, Repair, Accident etc) and car event description and so on. VehicleDetails covers basic car information.

struct VehicleEvent {
string date;
int eventType;
string eventdescription;
string odometerreading;
string location;
}

struct VehicleDetails {
string vin;
string make;
string model;
string yearofmanuf;
string odometerreading;
string ownerType;
string description;
string fuelType;
}

Then we define two maps, storing car events and car information for a given car VIN (Vehicle Identification Number, a unique number for every car).

mapping (string => VehicleEvent) private vehicle_events;

mapping (string => VehicleDetails) private vehicle_details;

Next, two functions, getCountofVins and getVinByIndex that return number of cars and car details for a given VIN respectively. We define a Solidity event, namely, vehicleAccident that is triggered when a car meets an accident. We also define vehicleEvent that is triggered when any car event occurs. Finally, we provide a function vehicleUpdate that is called by an application to notify us whenever any car event occurs.

Compile and Deploy Smart Contract

Before any Smart Contract can be used, it needs to be compiled and deployed on Ethereum. So, use solc (you can download from here) command as shown below.

solc --bin --abi VehicleStateContract.sol -o .

It will generate two files, a namely a binary file that has to be deployed on geth node and an abi file that defines all the functions and events the smart contract exposes along with parameter info. The abi file can be used by client applications for interacting with this smart contract.

You can deploy a smart contract using various client libraries. Here is a sample HTML file that uses web3.js (download from here) to do the deployment.

<html>
<script src="js/web3.js"></script>
<script>

// set the provider you want from Web3.providers
var web3 = new Web3(new Web3.providers.HttpProvider("http://IP Address of Node#2:8042"));

// Put Contract Binary code here
var contract_binarycode = '0x6060604052a83b0029.................';

// Put Contract ABI JSON here
var contract = web3.eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"vin","type":"string"},{"name":"vehicleDetails","type":"string"},{"name":"vehState","type":"int256"}],"name":"vehStateChanged","outputs":[],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"vin","type":"string"}],"name":"vehicleAccident","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"vin","type":"string"},{"indexed":false,"name":"vehState","type":"string"}],"name":"vehicleState","type":"event"}]);

contract.new({
from: web3.eth.accounts[0],
data: contract_binarycode,
gas: 900000,
}, function(err, res) {
if (err) {
console.error('there was an error: ' + err);
return;
}
         // Transaction hash
console.log('Transaction hash: ' + res.transactionHash);
         if (res.address) {
console.log('Contract address: ' + res.address);
}

});
</script>
</html>

A smart contract is deployed on a Blockchain like a transaction, so you have to specify the sender’s account as well as gas limit for the transaction while deploying it.

Build Client Application

Now, we have reached the final part of our exercise where we will build a Client API that internally integrates with above smart contract. For this purpose, we will use Web3j, a Java library that supports integration with Ethereum client nodes (such as Geth) using RPC-JSON over HTTP. Web3j provides utility commands that generate Java classes so that you can easily integrate with smart contracts. To do so, run the following command.

web3j solidity generate VehicleStateContract.bin VehicleStateContract.abi -p com.test -o .

It will generate a Java class VehicleStateContract.java under com.test package.

Now, let’s write an API that retrieves all cars from our Blockchain. Here is the code for same.

private Vehicle[] getVehicles() {
String nodeURL = "http://IP Address of Node#2:8042";
String walletPassword = "1234";
String walletFile = "D:\\ethereum\\blockdata\\keystore\\UTC--2017-08-16T08-53-06.687728900Z--656125a143bdf0774b3e1861a462eba0a3eb7766";
String contractAddress = "0xa2c82ab7b0fbb4d644d8b583ac289fc8c22a4d87";
Web3j web3j = Web3j.build(new HttpService(nodeURL));
try {
//Get credentials of account that will be used to load and invoke functions of smart contract 
Credentials cred = WalletUtils.loadCredentials(walletPassword, walletFile);
} catch (IOException | CipherException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Load the smart contract
VehicleStateContract vehicleContract = VehicleStateContract.load(contractAddress, web3j, cred, org.web3j.tx.ManagedTransaction.GAS_PRICE, org.web3j.tx.Contract.GAS_LIMIT);
Vehicle[] vehicles = null;
String vin;
try {
int countOfVehicles = vehicleContract.getCountofVins().get().getValue().intValue();
System.out.println("Number of vehicles: " + countOfVehicles);
vehicles = new Vehicle[countOfVehicles];
for (int i=0; i < countOfVehicles; i++) {
vin = vehicleContract.getVinByIndex(new Uint256(i)).get().getValue();
System.out.println("VIN is " + vin);
vehicles[i] = this.getVehicle(vin);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return vehicles;
}

Here are few things you may note.

  • You have to lookup a smart contract using a contract address (that you received while deploying the smart contract), the account password and it’s corresponding wallet file. In a production system, you will store the account details in a secure system and then pass on same to web3j at runtime.
  • It is difficult to remember the contract address. Therefore, in future, we will build a registry that returns contract address for a given contract name, using, what else, another smart contract !!
  • Your Client API connects to Node#2 for all operations on our smart contract. If it is a transaction operation, for which gas needs to be paid, the transaction is first submitted on Node#2 and then it is broadcast to Node#1 (miner node). Sometimes, you may notice that transaction is not being broadcast to miner node. If that happens, go to Node#2, start mining (using miner.start()) and afterwards, stop mining on Node#2. New transactions would continue to get broadcast to Node#1 even if mining has been stopped on Node#2.

If you want to write an API that returns the entire list of car events for a given VIN, here is the code for same.

VehicleStateContract vehicleContract = VehicleStateContract.load(contractAddress, web3j, cred, org.web3j.tx.ManagedTransaction.GAS_PRICE, org.web3j.tx.Contract.GAS_LIMIT);
vehicleContract.vehicleEventEventObservable(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST).subscribe(new Action1<VehicleEventEventResponse>() {
public void call(VehicleEventEventResponse eventResponse) {
VehicleEvent event;
System.out.println("***********************   VIN is " + eventResponse.vin + " *************");
if (vin.equals(eventResponse.vin.toString().trim())) {
event = new VehicleEvent();
event.setDate(eventResponse.date.getValue());
event.setDescription(eventResponse.eventdescription.getValue());
event.setLocation(eventResponse.location.getValue());
event.setName(getEventName(eventResponse.eventType.getValue().intValue()));
event.setOdometer(eventResponse.odometerreading.getValue());
event.setVin(vin);
eventHistory.add(event);
}
}
}
);

Here is the code to add a new car event in your Blockchain.

public String addVehicleEvent(VehicleEvent event) throws Exception {
VehicleStateContract vehicleContract = VehicleStateContract.load(contractAddress, web3j, cred, org.web3j.tx.ManagedTransaction.GAS_PRICE, org.web3j.tx.Contract.GAS_LIMIT);
vehicleContract.vehicleUpdate(new Utf8String(event.getVin()), new Utf8String(event.getDate()), new Int256(new Long(event.getName()).longValue()), new Utf8String(event.getDescription()), new Utf8String(event.getOdometer()), new Utf8String(event.getLocation()));
return "Success";
}

Finally, let’s trap Accident events whenever they occur in a car. As you can see from below, it uses ReactiveX Observable pattern and wait for Accident events to occur. When such an event occurs, the callback function call is invoked with parameters as those sent by Solidity event. For example, smart contract can send the VIN# that can then be used for further processing with Insurance company.

public void vehicleAccidentCallback() {
TestVehicleStateContractV3 vehicleContract = TestVehicleStateContractV3.load(contractAddress, web3j, cred, org.web3j.tx.ManagedTransaction.GAS_PRICE, org.web3j.tx.Contract.GAS_LIMIT);
vehicleContract.vehicleAccidentEventObservable(DefaultBlockParameterName.LATEST, DefaultBlockParameterName.LATEST).subscribe(new Action1<VehicleAccidentEventResponse>() {
public void call(VehicleAccidentEventResponse eventResponse) {
System.out.println("***********************   VIN # " + eventResponse.vin + " has encountered an accident *************");
// Connect with Insurance system and raise a claim againt VIN#
}
}
);
}

You can expose these Client APIs as RESTful APIs over HTTP(S) so that they can be invoked by actual car devices.

I hope this article was useful to you. In a future article, I shall explore some other Blockchain framework — such as Chain Core and BigchainDB — and show you how to build similar application using those frameworks.