1. Overview
In this tutorial, we’ll learn how to create a simple blockchain using Kotlin.
We’ll implement a rudimentary chain similar to Bitcoin to learn how this technology works. While we’ll be using Kotlin, the main concepts in this article are universal and don’t depend on Kotlin.
2. Understanding Blockchain Technology
Let’s briefly explore the concept of a blockchain. However, we won’t investigate all the theoretical details. We’ll describe a simple blockchain to showcase how this technology works.
A blockchain is a decentralized (or distributed) storage system consisting of blocks. Moreover, each block contains various elements that allow the creation of a chain-like structure where each block links to a specific instance of all the previous nodes. This linkage ensures data integrity across the network, as transactions can occur directly between various users without a central mediator.
Now, we cannot add blocks to the blockchain whenever we want. Instead, we need to mine blocks. Briefly, mining a block is similar to solving a really hard problem. If someone solves this problem, they get to add a new block to the chain. Otherwise, they keep trying to find a solution.
Additionally, the mining process regulates the rate at which we add new blocks to the blockchain. For example, Bitcoin dynamically adjusts the complexity of the problem to regulate the speed at which blocks are mined on average.
Let’s visualize a blockchain with a diagram that contains four blocks:
We see that hashes in the blocks help create the chain or links between blocks as each consecutive block holds the previous block’s hash.
Moreover, each block contains a data payload, which is the core utility of the blockchain. In a cryptocurrency like Bitcoin, this data typically stores financial transactions — for example, the sender, recipient, and amount of a cryptocurrency transfer.
Finally, we can see we have different values of nonce. As more nodes join the network and try to mine blocks, the blocks are found faster on average. To maintain a consistent block addition rate, the nonce adjusts, increasing the difficulty of finding a valid hash.
Now, let’s create this blockchain.
3. Implementing a Blockchain Using Kotlin
Let’s move on to a basic implementation to understand the parts of a blockchain.
3.1. Defining the Block Structure
First, we need to define the structure of the blocks that will make up our Blockchain. So, we want our blocks to contain a cryptographic hash of the previous block, a timestamp, transaction data, nonce, and the current hash value of the block itself:
data class Block(
val previousHash: String,
val data: String,
val timestamp: Long = System.currentTimeMillis(),
val nonce: Int = 0,
val hash: String
)
Here, we define the block using a data class, and all properties are final. This enforces immutability, which aligns with the fundamental principles of blockchain technology. A block’s content cannot be altered once it’s been created and added to the blockchain. This makes our blockchain trustworthy within a decentralized context, guaranteeing that the data cannot be tampered with.
Now, the class we created correctly models a blockchain block. However, the hash parameter must be computed within the block based on its content so we can ensure data integrity. So, instead, we’ll create a hash function named calculateHash() and use it to initiate the hash lazily.
To generate the hash value, we want to use all the string values of the fields of our Block:
data class Block(
val previousHash: String,
val data: String,
val timestamp: Long = System.currentTimeMillis(),
val nonce: Int = 0
) {
val hash: String by lazy { calculateHash() }
fun calculateHash(): String {
val input = "$previousHash$data$timestamp$nonce"
return input.sha256()
}
}
3.2. Hash Function
Now, we need to implement a hashing function that we’ll use to create the hash. In short, a hash value is just a mapping of some input data — in our case, a string value — to a fixed-size string that is highly sensitive to any change in the input data, no matter how small.
Inspired by Bitcoin, we’ll use a SHA-256 hash function to calculate the hash of a given string:
fun String.sha256(): String {
val bytes = this.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val digest = md.digest(bytes)
return digest.fold("") { str, it -> str + "%02x".format(it) }
}
3.3. Mining Blocks
Before we can create a chain of our blocks, we need to implement mining logic.
Specifically, mining involves performing a computationally intensive task that requires finding a hash that meets specific criteria — for example, a hash value that starts with a certain number of zeros.
Also, every time a new calculation is made, we want to adjust the nonce variable in the block.
Let’s add another method to allow the mining of new blocks:
fun mineBlock(previousHash: String, data: String, acceptingRegexp: Regex): Block {
var finalBlock = Block(previousHash, data)
while (!finalBlock.hash.matches(acceptingRegexp)) {
finalBlock = finalBlock.copy(nonce = finalBlock.nonce + 1)
}
return finalBlock
}
We defined a mineBlock() function that takes the hash value of the previous block, the data for the new Block, and a regular expression representing the acceptance criteria for the calculated hash for the new block. In our example, we’ll let the Blockchain manage the acceptance criteria. When mining, we continuously loop over and increase the nonce value until we find the hash that satisfies our acceptance criteria.
4. Creating a Blockchain
Now that we have the building blocks, we’ll create a simple blockchain. In short, a blockchain is nothing more than a list of blocks, each securely linked to the previous one via the hashes:
class Blockchain(difficulty: Int = 5) {
val chain = mutableListOf()
val acceptanceRegex = "^[0]{$difficulty}.+".toRegex();
init {
val genesisBlock = mineBlock("0", "Genesis Block", acceptanceRegex)
chain.add(genesisBlock)
}
}
Here, we define a Blockchain with a default difficulty of 5, which can be computationally expensive for some older devices. The difficulty controls our acceptance criteria and declares the number of zeros our hash must start with.
An instance of Blockchain will initialize the blockchain itself, mining the first block named “Genesis Block” and adding it to the chain.
Next, let’s create an addBlock() function to allow the addition of new blocks:
fun addBlock(block: Block) {
if (isValidBlock(block)) {
chain.add(block)
} else {
throw IllegalArgumentException("Invalid block")
}
}
Before adding the Block to the chain, we need to verify whether the block is valid or not. If it isn’t, we’ll throw an exception and not alter the blockchain. The isValidBlock() method checks whether the previous hash values match the last block’s hash value as well as whether the current block passes the acceptance criteria:
private fun isValidBlock(block: Block): Boolean {
val lastBlock = chain.last()
return block.previousHash == lastBlock.hash &&
block.hash.matches(acceptanceRegex)
}
4.1. Validating the Blockchain
Finally, let’s look at the logic to verify whether a block is valid:
fun isValid(): Boolean {
if (chain.size < 2) return true chain.zipWithNext().forEach { (prev, current) ->
if (current.previousHash != prev.hash) {
return false
}
}
return true
}
This method checks the integrity of a blockchain. Furthermore, it ensures that each block in the chain correctly points at its predecessor by checking that the previousHash of each block matches the hash of the block before it. If these hashes don’t line up, it means our Blockchain was tampered with.
5. Simulating a Blockchain
Let’s create a blockchain instance and simulate adding some blocks to it:
fun main() {
val blockchain = Blockchain(3)
val block1 = mineBlock(blockchain.chain.last().hash, "Block 1 Data", blockchain.acceptanceRegex)
blockchain.addBlock(block1)
val block2 = mineBlock(blockchain.chain.last().hash, "Block 2 Data", blockchain.acceptanceRegex)
blockchain.addBlock(block2)
val block3 = mineBlock(blockchain.chain.last().hash, "Block 3 Data", blockchain.acceptanceRegex)
blockchain.addBlock(block3)
println("Blockchain valid? ${blockchain.isValid()}")
blockchain.chain.forEach {
println("Block Data: ${it.data}, Hash: ${it.hash}")
}
}
Executing this code might take quite some time depending on the computational power of our machine. Once finished, it will print the integrity check of the blockchain along with its contents:
Blockchain valid? true
Block Data: Genesis Block, Hash: 00000085499efc933ea985f32aeb11b5ee10fc1d161e8a5dea01b0ef49f79546
Block Data: Block 1 Data, Hash: 00000ac71dfc0d648d78ce283d526039eb3023c8d59a95ef58d1c7fa623f6067
Block Data: Block 2 Data, Hash: 000000b095a3492f6f64cf7a8de7854b009ad4385e9a469d08c7e8934b93845e
Block Data: Block 3 Data, Hash: 00000d0fd52e7cc6ada4e198c8682db7bce515a0aad03bdcec62e9f3d3e1c536
6. Conclusion
In this article, we’ve learned how to create a simple blockchain using Kotlin. First, we learned the basics of the blockchain technology. Then, we implemented a hash function followed by the building blocks of our blockchain.
Additionally, we created a Blockchain class to represent an instance of the blockchain. Finally, we created an instance of a blockchain and added data to see how it works.
As always, the complete code can be found over on GitHub.