This post is continuation of the first part of creating a simple blockchain in Kotlin which you can find here. This time I’ll improve the Kotcoin blockchain with implementation of proof of work and block validation. We’ll also make it public, so anyone can mine and see what’s being stored in the network.
Understanding proof of work
Basically a proof of work is a generated data piece using complex, time-consuming operations that are easy to verify. Producing proof of work should be a difficult and rather random process so it takes a fair amount of time to finish. The result of this operation is creation of new block. The user that performs this operation is called a miner and the blockchain network, in return of completing the act of mining, rewards the miner with a block. The Bitcoin implementation uses the Hashcash algorithm. If you want to learn more about proof of work, bitcoin wiki is a really good source. But let’s get back to code!
Implementing proof of work and block validation
The Block has to be extended with another Integer property called proofOfWork in which the generated PoW will be stored.
class Block(val index: Int, val previousHash: String, val data: Any, val proofOfWork: Int)
The next step is creating a method for generating proof. Remember that the more blocks in the network, the harder the operation should be, hence the optional difficulty parameter. In this case I’ve implemented a simple algorithm which finds the next value divisible by [9 multiplied by difficulty level]. In Blockchain.kt:
private fun generateProofOfWork(previousPow: Int, difficulty: Int = 1): Int { var proof = previousPow + 1 val nonce = 19 * difficulty while ((proof + previousPow) % nonce != 0) { proof += 1 } return proof }
Do you remember what’s one of the main assumptions of blockchain? The validity of each new generated block. Therefore we need to complement the implementation of Kotcoin with a new method that takes care of validating the correctness of new block.
private fun isNewBlockValid(newBlock: Block): Boolean = ((newBlock.index == getLatestBlock().index + 1) && (newBlock.previousHash == getLatestBlock().hash))
This methods takes a Block as the argument and checks if it’s in the correct position in the chain and if the previous block’s hash is equal to the property previousHash in new block.
Exposing KotCoin to the public
We are kind of missing the point of blockchain if it’s just available on our computer. One of the implementation basics is making it decentralised and allowing peers (nodes) in the network to talk. Right now I’m not going to implement the whole transaction logic, but I thought I want to try something new in Kotlin and decided to use JavaLin to make KotCoin publicly available.
JavaLin advertises itself as a lightweight Java and Kotlin web framework (hence the name, I believe). Let’s start with adding the dependencies to Gradle build file:
compile 'io.javalin:javalin:1.5.0' compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+"
The documentation on their website is really simple and straightforward so I have no problems setting everything up. Starting the server takes only about 20 characters in the main application method: Javalin.start(port)
Before creating RESTful endpoints, we should make use of methods created above: generateProofOfWork and isNewBlockValid. I’ve created additional method called mineBlock that takes any data as a parameter.
fun mineBlock(data: Any): Block { val proofOfWork = generateProofOfWork(getLatestBlock().proofOfWork) val block = Block(chain.size, getLatestBlock().hash, data, proofOfWork) addNewBlock(block) return getLatestBlock() } fun addNewBlock(block: Block) { if (isNewBlockValid(block)) chain.add(block) }
I think everything is pretty clear here – firstly the chain generates proofOfWork for new block, then creates new Block object and finally adds it to the chain. The new block is not going to be added if the validation fails. After that, the method returns the latest element in the chain.
Now, back to the main method of the project. Javalin.start(port) returns a running application instance. Basing on this instance, we have multiple configuration methods available but in our case the most important is routing.
val kotcoin = Blockchain fun main(args: Array<String>) { val app = Javalin.start(7000) app.routes { path("blocks") { get({ ctx -> ctx.json(kotcoin.chain) }) path("mine") { post({ ctx -> val minedBlock = kotcoin.mineBlock(ctx.body()) ctx.json(minedBlock) }) } } } }
I fell in love with JavaLin because of the code snippet above. 🙂 With just few lines of code I’ve set up and started a full-fledged service for handling basic chain operations.
But it seems like there’s a lot of indentation which I personally do not like. No worries, there’s another, cleaner, way:
val kotcoin = Blockchain fun main(args: Array<String>) { val app = Javalin.start(7000) app.get("/blocks") { ctx -> ctx.json(kotcoin.chain) } app.post("/blocks/mine") { ctx -> val minedBlock = kotcoin.mineBlock(ctx.body()) ctx.json(minedBlock) } }
The first endpoint allows to obtain every existing block in the chain. The second one is a POST HTTP method which mines a block. It takes the request body and puts it as the data of mined block. After mining, it returns the details of block. Let’s run the main method and access both endpoints through REST client.
As you can see, everything works like charm. The first screenshot shows the state of KotCoin after initialization, the second one contains the data about first mined block (note that I passed “KotCoin first mined block” as the request body) and the last picture presents the state after mining the block. (btw. the REST client I use is the one built-in in IntelliJ Idea)
Current state of KotCoin
Right now KotCoin
- contains blocks that store data and are chained together
- exposes public API so anyone can see what’s in the network and mine new blocks
- requires computing proof of work in order to mine
- ensures that the chain is valid
You can find the whole source code of KotCoin on my GitHub.
In the near future I’ll extend KotCoin with characteristics of decentralised network. If you want to be notified about new posts, follow me on Twitter: @a_mrszlk