I find that I’m enjoying the theory behind blockchain and am tempted to continue along the path of exploring the different implementations, consensus algorithms, and pros and cons. However, now that there’s a basic understanding of why we would/should look at it, and some fundamental knowledge of how it works, it seemed a good idea to actually build something - I’ve heard many people complain about the amount of theory they’ve seen but how little they’ve seen in the way of anything having been developed.
In that spirit, I’ve come up with a contrived (but practical) example that I will implement: I would like to provide proof that a vehicle I drive actually belongs to me and that the history of that vehicles’ ownership can be traced.
I’m opting to develop this for Ethereum, but the same thing could be done on Quorum or Fabric, among others. In future posts, I’ll explore these platforms too - so stay tuned.
The source code for this application can be found here.
Firstly, ensure that you have some prerequisites setup: I’ll be using the Truffle Framework - I like the scaffolding it provides and it makes my life as a developer easier with contract compilation, automated testing and scriptable deployments and migrations. My test net will be using Ganache. Visual Studio Code will be used as my IDE along with the Solidity Language Extension.
Once you have that all setup, lets begin.
I want to store some details of the vehicle:
- What the owner's address is (the address, in this context, is the blockchain address)
- The owners name
- Registration
- VIN
- Make; and
- Model
In my “contracts” folder I’ll create a contract called Vehicle.sol and, similar to a usual class, define my properties. Simplistically, consider a contract as the template that defines what information you want stored on the blockchain and how you want to interact with that information.
A vehicle needs an owner on creation so who ever creates the vehicle, the first time, will be the owner and I only ever want the owner to have the ability to transfer that vehicle to a purchaser - I’ve used the modifier for this purpose - in that case it check that the entity executing the function is the owner.
Below is what my contract looks like.
The very first line (pragma solidity….) specifies the minimum version of solidity that’s required to compile this contract. This will prevent future compiler versions from compiling the contract where there may be incompatible changes.
You’ll notice functions to: create a vehicle - This will be used when I create a vehicle and will set the values for some properties, for example, who the owner is. change the owner - in particular, when the vehicle is sold, ownership transfers to the purchaser.
I’ve also got a strConcat function which is the best implementation I’ve come across (so far) to handle string concatenations in solidity.
Ensure Ganache is running then switch over to terminal and run truffle compile.
Once our contract has compiled we can now deploy it to our Ganache testnet by running this truffle migrate.
This gives us the following output:
It may be the case where you receive an error like this
In this case, truffle was unable to detect the network you’re attempting to deploy to. All that’s required to correct this is the addition of network settings to truffle.js
More configuration information can be found here.
If you look at the output, you’ll notice that the migrations were run, but…. There’s no mention of the contract just created!
What we’re missing is the instruction to deploy the Vehicle contract. To do this, we need to create a migration. This migration will then, automatically, be executed when calling truffle migrate. The migration files need to be numbered sequentially - when looking at the project, you’ll notice there’s already a 1_initial_migration.js file. We will add our own and call it 2_vehicle_contract.js.
The migration code is relatively simple and looks as follows:
It is important to note that ‘require’ needs to provide the actual name of the contract and not the file name, as a file can contain multiple contracts.
Once you’ve got this in place, running truffle migrate migrates this contract and the output look like this:
If you switch to Ganache, you’ll notice that the current block has advanced and taking a look at “transactions” reveals our contract deployments.
I’m going to use truffle console to interact with my contract - Truffle console is a basic interactive console that can connect to any Ethereum client. I’ve opted to use console because I already have a network deployed in the form of Ganache - if this wasn’t the case, I would use truffle develop.
Navigating to the path of our project using terminal, execute truffle console. This spins up the interactive console.
The first thing we need to do is determine where the contract is (i.e. the address of my contract). Using truffle, this is easily done by running truffle networks from within the truffle console. This lists the contracts I have and their addresses.
Using the address we can then call our function createVehicle(…) like this:
Lets now discover who the owner is by calling the OwnerName property.
We can also see the owners address.
Lets now sell our vehicle to a purchaser. In this contrived example, running on a test network, that’s going to be enacted by the owner transferring the vehicle to someone else. Recall, that only the owner can execute the changeOwner function.
I’m going to select a random address from Ganache (that’s not currently the owner) and use that as the new owner.
Let’s check the new owner and the address.
So our contract works and we can at any time, determine who the owner is or look at any of the other properties.
You would have noticed that there was an event recorded in the code, and looking at the output from the function call after changing owners, there was an “event” property that alluded to the code tying up with this property. Let dig into that event to see what’s recorded.
We do this by first getting all the events from the beginning of time then outputting those events
We can then see out event - Owner Changed - is the last entry in the logs.
Be aware, that typically, this is not how you handle events. Yes, it can be used to store some information like you see here. However, you would usually have other DApps listening for and responding to these events. Also, in a production environment, be cautious of querying events in this way as it has been reported to (sporadically) crash your JSONRPC endpoint. Read more here.
So folks, there you have it, a really simple Distributed Application (DApp) that stores some data and queries it.
In the next post I’ll dig a deeper into consensus algorithms; why we should care what they are and what they mean to developers.