Blockchain 0x100 – Developing the Core Blockchain Structure
If you are into Web3 development, the term blockchain is not a new thing to you. In the last blog post of this series, I explained most of the core concepts behind how a blockchain works — distributed ledgers, hashing, consensus mechanisms, and all that good stuff. Learning the theory is a good start. But it only gets you so far. To really understand blockchains, you have to build one yourself.
So guys, in this tutorial, I’m starting a long journey. Yes, as the title says, we’re going to build a blockchain. No Ganache, no external networks. We’re building one completely from scratch, in Java.
By the end of this article, you’ll have a working blockchain that can create blocks, mine them with Proof of Work, chain them together, and validate the integrity of the entire chain. Let’s get into it.
The CryptoUtils Class — Our Hashing Tool
Before we build blocks, we need a utility to generate SHA-256 hashes. Remember from the previous article — a hash is a digital fingerprint. Feed in some data, and the hash function spits out a unique, fixed-length string. Change even a single character, and the entire output changes.
Here’s our CryptoUtils class:
public class CryptoUtils {
public static String applySha256(String input) {
try {
MessageDigest digest = MessageDigest.getInstance(“SHA-256”);
byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) {
hexString.append(‘0’);
}
hexString.append(hex);
}
return hexString.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
What’s happening here? We’re using Java’s built-in MessageDigest class to compute a SHA-256 hash. The input string gets converted to bytes, hashed, and then converted back to a hexadecimal string. That hex string is our fingerprint — a 64-character output no matter how long or short the input is.
We’ll be calling CryptoUtils.applySha256() throughout our blockchain. Think of it as the foundation everything else sits on.
Creating the Block Class
We learned a lot of deep concepts in the previous tutorial, but for now, let’s keep things simple. The most basic element of a blockchain is the block. The entire chain is just a sequence of these blocks linked together.
So, what kind of data does a block need to hold?
From our previous discussion, a block needs to store a timestamp, data, nonce, and hashes. Recall the following diagram.

Let’s start by creating a Block class in Java. Here’s the structure of it:
public class Block {
private String data;
private int nonce;
private int difficulty;
private long timestamp;
private String hash;
private String prevHash;
}
So what’s going on here? Each block needs to store a few key pieces of information.
- data — holds whatever information we want to record (transactions, messages, anything!)
- timestamp — tells us when the block was created
- prevHash — stores the hash of the previous block (this creates the “chain” in blockchain)
- hash — this block’s unique fingerprint
- nonce and difficulty — work together to make mining possible (we’ll explain this soon)
Now properties are done. We need some methods for the class. Please note that I’m not going to show the getters for these properties as the code gets much larger if I do so. When you are implementing this on your own, you might need to add them.
Calculating the Hash
We need a way to calculate a block’s unique hash. The hash acts as an immutable fingerprint for the block.
public String calculateHash() {
String dataToHash = data + nonce + difficulty + timestamp + prevHash;
this.hash = CryptoUtils.applySha256(dataToHash);
return hash;
}
What’s happening here? We’re taking all the block’s properties, combining them into one long string, and then running it through our CryptoUtils.applySha256() method.
If even one character of data changes, the resulting hash will be completely different. This is what gives blockchains their immutability. If anyone tries to modify a block, its hash won’t match anymore, and the entire chain becomes invalid.
Mining the Block
Now let’s talk about mining. Mining is what makes blockchain secure. It requires computational work to add a new block, which makes it really hard for attackers to mess with the chain. Here’s our mining method:
public void mineBlock() {
String target = “0”.repeat(difficulty);
nonce = 0;
hash = calculateHash();
while (!hash.startsWith(target)) {
nonce++;
hash = calculateHash();
}
System.out.println(“Block mined with the hash : “ + hash);
}
What’s happening?
We’re searching for a hash that starts with a certain number of leading zeros — this is our Proof of Work. The number of zeros is determined by the difficulty. With a difficulty of 4, we need a hash that starts with 0000.
Each time we increment the nonce and recalculate the hash until it matches the target. Once it does, the block is considered “mined.”
Why does this matter? Because finding a valid hash is hard (it’s basically brute-force guessing), but verifying it is easy. Anyone can look at the hash and immediately confirm it starts with the right number of zeros. This asymmetry — hard to produce, easy to verify — is the backbone of blockchain security.

Block Constructor
Here’s the constructor that ties everything together.
public Block(int index, String data, int difficulty, String prevHash) {
this.data = data;
this.difficulty = difficulty;
this.prevHash = prevHash;
this.timestamp = Instant.now().toEpochMilli();
mineBlock();
}
Notice something? We call mineBlock() right inside the constructor. That means every time a new block is created, it’s mined before it gets added to the chain. No shortcuts.
Mining ensures that adding a block requires computational effort, making the blockchain expensive to tamper with — you’d have to re-mine every block after the modified one to fake the chain successfully.
Building the Blockchain Class
Now that our Block class is ready, it’s time to build the Blockchain itself — the system that manages and connects all blocks.
We’ll store all blocks in an ArrayList, starting with a Genesis Block, which is the very first block in the chain.
public class Chain {
private final int difficulty = 4;
private final ArrayList<Block> blockchain = new ArrayList<>();
public Chain() {
blockchain.add(new Block(0, “Genesis block”, difficulty, “0”));
}
}
That’s our starting point. The Genesis Block is created manually and doesn’t link to any previous block — its previous hash is simply ”0”. Every blockchain has one. Think of it as block zero, the anchor of the entire chain.
Adding New Blocks
Now, let’s add a method to create and append new blocks to our chain.

public Block getLatestBlock() {
return blockchain.get(blockchain.size() - 1);
}
public void addBlock(String data) {
Block newBlock = new Block(blockchain.size(), data, difficulty, getLatestBlock().getHash());
blockchain.add(newBlock);
}
This method takes new data, grabs the hash of the latest block, and uses it as the prevHash for the new block. The new block gets mined automatically (remember the constructor?), and then it’s appended to the chain. That’s it — our chain grows one block at a time, each one cryptographically linked to the last.
Validating the Chain
Here’s the thing — building a blockchain is one thing, but how do we know nobody has tampered with it? We need a way to verify the integrity of the entire chain. This is where isChainValid() comes in:
public boolean isChainValid() {
for (int i = 1; i < blockchain.size(); i++) {
Block currentBlock = blockchain.get(i);
Block previousBlock = blockchain.get(i - 1);
if (!currentBlock.getHash().equals(currentBlock.calculateHash())) {
System.out.println(“Block “ + i + “ has been tampered!”);
return false;
}
if (!currentBlock.getPrevHash().equals(previousBlock.getHash())) {
System.out.println(“Block “ + i + “ is not linked properly!”);
return false;
}
}
return true;
}
What’s this doing? It walks through every block in the chain and checks two things:
-
Hash integrity — Does the block’s stored hash match what we get when we recalculate it? If someone changed the data, the recalculated hash won’t match the stored one. Tampering detected.
-
Chain linkage — Does the block’s
prevHashactually match the previous block’s hash? If someone inserted, removed, or reordered blocks, this link breaks. Chain broken.
If both checks pass for every single block, the chain is valid. If even one fails, the whole thing is compromised. This is the beauty of the hash chain we talked about in the previous article — one change cascades through the entire chain.
Printing the Chain
Let’s also add a utility method to visualize our blockchain:
public void printChain() {
System.out.println(“------------------------”);
System.out.println(“Printing the blocks”);
for (int i = 0; i < blockchain.size(); i++) {
System.out.println();
System.out.println(“Block : “ + i);
System.out.println(“Previous Hash : “ + blockchain.get(i).getPrevHash());
System.out.println(“Current Hash : “ + blockchain.get(i).getHash());
}
System.out.println(“------------------------”);
}
Nothing fancy here — just iterating through the chain and printing each block’s index and hashes. But it’s incredibly useful for debugging and seeing the chain structure in action.
Putting It All Together
Time to see our blockchain in action. Here’s the Main class:
public class Main {
private static Chain blockchain = new Chain();
public static void main(String[] args) {
blockchain.addBlock(“test Data 1”);
blockchain.addBlock(“test Data 2”);
blockchain.addBlock(“test Data 3”);
blockchain.printChain();
}
}
When you run this, you’ll see something like:
Block mined with the hash : 0000a4f2e8c1d9...
Block mined with the hash : 00007b3d91f0e2...
Block mined with the hash : 0000c8e5a2b7f1...
Block mined with the hash : 00003f9d12e4a8...
------------------------
Printing the blocks
Block : 0
Previous Hash : 0
Current Hash : 0000a4f2e8c1d9...
Block : 1
Previous Hash : 0000a4f2e8c1d9...
Current Hash : 00007b3d91f0e2...
Block : 2
Previous Hash : 00007b3d91f0e2...
Current Hash : 0000c8e5a2b7f1...
Block : 3
Previous Hash : 0000c8e5a2b7f1...
Current Hash : 00003f9d12e4a8...
------------------------
See how each block’s Previous Hash matches the Current Hash of the block before it? That’s the chain in action. Every block is cryptographically linked to the one before it. Break one link, and the whole thing falls apart.

Also notice all hashes start with 0000 — that’s our difficulty of 4 at work. The miner had to try thousands of nonces to find each of those hashes. Bump the difficulty up to 5 or 6, and watch the mining time increase exponentially.
Wrapping Up
Let’s take a step back and look at what we’ve built. In just four classes, we have a working blockchain:
- CryptoUtils — handles SHA-256 hashing
- Block — stores data, computes hashes, and mines itself using Proof of Work
- Chain — manages the sequence of blocks, validates integrity, and grows the chain
- Main — ties it all together
It’s simple, but the core principles are the same ones powering Bitcoin, Ethereum, and every other blockchain out there. Hashing, chaining, mining, validation — we’ve implemented all of it from scratch.
The full source code is available on GitHub: distributed-blockchain (branch 0x100)
But we’re not done yet. Right now, our blockchain stores simple strings as data. Real blockchains store transactions — Alice sending money to Bob, remember? In the next article, we’ll implement a proper transaction system with wallets and digital signatures. Things are about to get a lot more interesting.