If You Want To Understand Blockchain, See This Java Implementation | by Randal Kamradt Sr | Better Programming

Image by analogicus from Pixabay

I get a lot of questions about cryptocurrencies and their underlying mechanism, the blockchain. A lot of the time I have trouble explaining it succinctly, so I’m going to write a blockchain example to better understand it myself. This article is one of three that will talk about the constituent parts: the chain of blocks, peer-to-peer networking, and mining. I won’t be making a cryptocurrency from it, just the blockchain with some abstract unit of value.

Not trying to make a true cryptocurrency simplifies a number of things. There are no fees or rewards (mining is done for the pure enjoyment of it). Transactions don’t need to add up and users don’t need traditional wallets. What’s left after removing these things? An immutable list of ‘transactions’ that is verifiable and distributed.

I should give credit, much of the nomenclature that I’m going to use is from the implementation of Naivechain and Naivecoin. While those projects are also useful for understanding the blockchain, I wanted to tease apart the pieces a little better, not have a full cryptocurrency implementation, but still consider the ideas of transfer of value, and proof-of-work.

I will be using Spring Boot with WebFlux for an HTTP server, MongoDB for a database, and Kafka for a message queue to assist in implementing peer-to-peer networking. I won’t be using all the features of MongoDB, even indexes will be left out in the interest of brevity. I won’t go into HTTP security, anyone will be able to access all of the endpoints. If you plan on using these parts for your own cryptocurrency, you better be prepared to tune and bulletproof it.

I will be using reactive Java extensively, so if you need a refresher on that, you might look at my article Understanding Reactive Java.

The first thing to go over will be the block in the blockchain. A block has a few items of data; a link to the previous block in the chain, a timestamp, a nonce which is used as part of proof-of-work, an index, and a transaction. Here’s my implementation of the block:

There is an id field that is used by MonogDB to track all entities. The hash is calculated with the index, previousHash, timestamp, transactions, and nonce. I include a ‘wither’ for the hash since it must be calculated after the rest of the block is initialized. The nonce is normally incremented for each iteration while trying to overcome the difficulty. But in our case, there is no difficulty so the nonce is always zero. I’ve left those pieces in place to demonstrate how they might be used if we wanted to include the proof-of-work that wasn’t trivial. We will look more at proof-of-work later when we tackle mining.

There is also a ‘genesis block’ which is always the first block in the chain. All of its values are zero. When our server starts up, if the database is empty, it will insert this record. Technically, that shouldn’t happen but once per node when you first start it up. But it needs to be there as part of the correctness of the blockchain. For now, we only have one node, we will talk about nodes again when we get to peer-to-peer networking.

By itself, the block is not very useful. To give it purpose, we need to add some data to it. Then the usefulness of the block is to verify the data. In our case, the data is a list of transactions and the transaction is a very simple pair of items, an input contract, and an output contract. If we were making a cryptocurrency, these ‘contracts’ would be a ledger entry for a transfer from one account to another. We use the term ‘address’ to indicate an account.

For us, though, the contracts are just a string. Think of a contract between two people, and each side wants to ensure that it never changes. So we add it to a transaction and put it in the blockchain. Here’s my implementation of a transaction:

Not a lot to it. The hash value is calculated from the transaction ID and the data. The data is divided up into input and a list of outputs, and theoretically, the input should equal the outputs. But since our contract is just a string, there’s no way to enforce that. It is just another artifact of this possibly being the start of a cryptocurrency. The input value is signed by the private key of the initiator. Think of it as the initiator sending something of value to the addresses in the list of outputs.

How do these two things get put together? A user can enter a transaction, but how do they get collected into a block? We will talk more about miners later, but suffice it to say, the miner sweeps all ‘loose’ transactions and makes a new block. Let’s take a look at some of the methods that we will use to manipulate the blockchain. Here’s my Blockchain class:

That’s not too much, most of it is dealing with blockchain hygiene. The block must be checked for four conditions; it must have an index one higher than the last block in the chain, it must have the hash of the last block as its previous hash value, its own hash must be reproducible from the data, and it must satisfy the difficulty level. Since we have no difficulty level, the last one is always true. It might seem odd that we’re checking if the hash that one might assume we just set is the same as a newly calculated one, but we must remember that in a distributed system, a new block might be added by a peer, so we need to protect against bad data from them.

We must also check each transaction in the block. That means that the hash is reproducible from the data and that the transaction exists nowhere else in the chain. We must also remove all transactions swept into this block from the transactions database, but that is done elsewhere.

Next, we have our service controllers. There are two service controllers: one for block and one for transactions. Included in both are some endpoints that will be moved elsewhere, but I present them here to test out the system before we move on. The extra endpoints allow you to create blocks as if you were a miner and to create transactions as if you were a user, both of which will be moved to a miner and user controller respectively. Here is the block controller as it stands now:

This controller has four endpoints, block for getting all blocks, block/last for getting the last block, block/{hash} for getting the block with a particular hash, and block/mine/{address} for pretending to be a miner. While the last endpoint belongs elsewhere as explained above, I include it here because it would be a pretty boring system if all we could ever see is the genesis block.

Then there is the controller for transactions. Normally, this would be used to look at ‘loose’ transactions, that is transactions that are not part of a block. Again, I added an endpoint to add a transaction even though that should only ever be done by a user. Here’s the transaction controller:

Here we only have three endpoints, transaction which will get all loose transactions, transaction/{transactionId} which will get a transaction of a particular ID, and transaction (as a POST) which will create a new transaction on behalf of a dummy user.

In order to run these endpoints, we need to start up MongoDB and Zookeeper/Kafka. Here is the docker-compose.yaml I use for that:

Starting up these services, and running the blockchain service, now we can visualize the blockchain. First, getting all blocks reveals the genesis block:

Now, let’s make a transaction:

Get the list of loose transactions:

Mine a block:

Get all blocks again:

You can also check to make sure that there are no more loose transactions.

This may not seem very exciting, it’s just a database of linked transactions. In my next article, I will cover the exciting part: a distributed system that functions together to form a consensus blockchain while leaving no transactions left behind. If all goes right, you should be able to add transactions or mine a block in any node. And eventually, all nodes will agree on the final blockchain.

All the code in this article can be found on my GitHub page here:

Related Articles

Back to top button

Adblock Detected

Please consider supporting us by disabling your ad blocker