The word "blockchain" gets thrown around a lot. Most explanations are either impossibly vague ("a distributed ledger!") or deep in cryptocurrency details that miss the core technical idea entirely.

At its heart, a blockchain is a data structure — a specific way of organising information so that it becomes extremely difficult to change any historical record without everyone noticing. That core idea is genuinely useful, interesting and worth understanding as a developer.

This guide skips the hype and explains exactly how blockchain works from first principles. We will build up from basic cryptographic hashing all the way to smart contracts, with working Python code at each step.

What Is Blockchain

Imagine you and a group of friends share a notebook. Every time anyone spends money, they write it in the notebook. The notebook is public — anyone in the group can read it. And crucially, every page is glued to the next one using a special ink that changes colour if someone tries to alter old entries.

A blockchain is that notebook, but for computers. It is a list of records (blocks) that are linked together cryptographically. Each block contains some data, a timestamp and a fingerprint of the previous block. This linkage means you cannot change old data without breaking all the blocks that came after it — and everyone can see the breakage.

Three properties make this powerful:

  • Immutability — once data is added to the chain it is practically impossible to alter without detection
  • Decentralisation — there is no single server that controls the chain. Thousands of computers each hold a copy
  • Transparency — on public blockchains, all transactions are visible to everyone

Cryptographic Hashing — The Foundation

Everything in blockchain depends on hashing. A hash function takes any input — a word, a document, a whole block of transaction data — and produces a fixed-length string of characters called a hash or digest. Think of it as a fingerprint of the data.

The Properties That Make Hashing Special

A good cryptographic hash function has four key properties that make blockchain possible:

  • Deterministic — the same input always produces exactly the same hash, every single time
  • Fixed size — no matter how long the input is (one word or a million words), the output is always the same length
  • Avalanche effect — changing even a single character in the input completely changes the output hash — not slightly, but entirely
  • One-way — given the hash, it is computationally impossible to figure out the original input. You cannot reverse it.

Hashing in Python

Python — demonstrating SHA-256 hashing
import hashlib def sha256(text): return hashlib.sha256(text.encode()).hexdigest() # Same input always gives the same output print(sha256("hello")) # 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 print(sha256("hello")) # 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 (identical) # Change ONE character and the hash is completely different (avalanche effect) print(sha256("Hello")) # 185f8db32921bd46d35c8d30c34da5d4e6b9e1eb2a46f3d7e1c5fa7425e73043 # Completely different — not just slightly different # Output is always exactly 64 hex characters (256 bits) regardless of input length print(sha256("a")) print(sha256("This is a very long piece of text with many words in it")) # Both outputs are exactly 64 characters long
ℹ️ SHA-256 is the hash function used by Bitcoin. SHA stands for Secure Hash Algorithm. The 256 means the output is 256 bits long, which gives 2256 possible outputs — a number so large that finding two inputs with the same hash by brute force is computationally impossible with any hardware that will ever exist.

Anatomy of a Block

A block is a container that holds a group of transactions (or any data) along with some metadata. Think of it like a page in that shared notebook. Each page has a page number, the date it was written, the content written on it, and a special seal at the bottom that incorporates the seal from the previous page.

Block Structure

Block #3
index: 3
timestamp: 2025-01-15T10:30:00Z
data: Robert sent 5 BTC to Divine
previous_hash: 00000a3f7b9c...
nonce: 84729
hash: 000002e1f4a8...
Block #2
previous_hash: 000009d2c1b7...
hash: 00000a3f7b9c...
Block #1 (Genesis)
previous_hash: 0000000000000000
hash: 000009d2c1b7...
Python — what a block looks like as a data structure
import hashlib import json from datetime import datetime class Block: def __init__(self, index, data, previous_hash): self.index = index self.timestamp = datetime.utcnow().isoformat() self.data = data # the actual content of the block self.previous_hash = previous_hash # the chain link self.nonce = 0 # used for mining (explained below) self.hash = self.compute_hash() def compute_hash(self): # Hash EVERYTHING in the block together as a single string content = json.dumps({ 'index': self.index, 'timestamp': self.timestamp, 'data': self.data, 'previous_hash': self.previous_hash, 'nonce': self.nonce }, sort_keys=True) return hashlib.sha256(content.encode()).hexdigest()

The Genesis Block

Every blockchain starts with a special first block called the genesis block. Since it is the first block there is no previous block for it to reference, so its previous_hash is set to a string of zeros by convention. It is the anchor that everything else builds on.

How the Chain Works

The chain is just a list of blocks where each block contains the hash of the block before it. This creates a cryptographic link. Block 3 contains the hash of Block 2. Block 2 contains the hash of Block 1. Block 1 contains all zeros.

Why It Is So Hard to Tamper With

Imagine someone tries to quietly change an old transaction in Block 2 — say, changing "Robert sent 5 BTC to Divine" to "Robert sent 0 BTC to Divine".

The moment they change any data in Block 2, the hash of Block 2 changes completely (remember the avalanche effect). But Block 3 is storing the old hash of Block 2 in its previous_hash field. Now Block 3's link is broken. To fix that, they would need to recalculate Block 3's hash too. And then Block 4's. And Block 5's. All the way to the end of the chain.

On a blockchain network, all of this would need to happen faster than the entire rest of the network is adding new blocks — while also having more computing power than everyone else on the network combined. In practice, this is economically and computationally impossible on large public blockchains.

Python — validating the chain integrity
def is_chain_valid(chain): for i in range(1, len(chain)): current = chain[i] previous = chain[i - 1] # Check 1: the stored hash matches what the hash should be if current.hash != current.compute_hash(): print(f"Block {i} has been tampered with!") return False # Check 2: this block's previous_hash matches the actual previous block's hash if current.previous_hash != previous.hash: print(f"Chain broken between block {i-1} and block {i}!") return False return True

Consensus Mechanisms — Who Gets to Add the Next Block

On a decentralised network, thousands of computers each have a copy of the blockchain. When a new block needs to be added, they all need to agree on which version is correct. This agreement process is called a consensus mechanism. Two major approaches exist.

Proof of Work

Proof of Work (used by Bitcoin) is basically a very hard maths puzzle. To add a new block, your computer must find a special number called a nonce that, when included in the block data and hashed, produces a hash that starts with a certain number of zeros.

Finding this nonce requires trying millions of random numbers until one works. The difficulty adjusts automatically so that on average it takes about 10 minutes per block across the whole network. The first computer to find the correct nonce gets to add the block and earn a reward.

Python — proof of work mining simulation
def mine_block(block, difficulty=4): """Keep trying different nonces until the hash starts with enough zeros.""" target = '0' * difficulty # e.g. "0000" for difficulty 4 block.nonce = 0 while not block.compute_hash().startswith(target): block.nonce += 1 block.hash = block.compute_hash() print(f"Block mined! Nonce: {block.nonce}, Hash: {block.hash[:20]}...") # The higher the difficulty, the more zeros required at the start, # and the longer it takes to find a valid nonce. # Difficulty 4 = hash must start with "0000" (fast) # Difficulty 6 = hash must start with "000000" (slower) # Bitcoin uses difficulty ~20 which takes serious hardware

Proof of Stake

Proof of Stake (used by Ethereum since 2022) takes a different approach. Instead of wasting energy on maths puzzles, validators lock up (stake) some of their own cryptocurrency as collateral. The network randomly chooses a validator to add the next block — but weighted by how much they have staked. If they try to cheat, they lose their stake.

This is like a security deposit. You put money on the line to prove you have something to lose. Behave honestly and you earn rewards. Try to cheat and you lose your deposit.

FeatureProof of WorkProof of Stake
Energy usageVery high (mining hardware)Low (no mining)
Security modelCost of hardware and electricityCost of staked tokens
Used byBitcoinEthereum, Cardano, Solana
Entry barrierNeed expensive hardwareNeed to own and lock tokens

Wallets and Keys — How Ownership Works

On a blockchain there are no usernames or passwords. Instead ownership is proven using public key cryptography. Every user has a key pair — a public key and a private key — and they work together like a lock and key.

Public and Private Keys

Your public key is your address on the blockchain. It is like your bank account number — you can share it with anyone. People use it to send you funds.

Your private key is the password that proves you own that address. Keep it completely secret. Anyone who has your private key can spend your funds. There is no "forgot my password" option on a blockchain. If you lose your private key, the funds are gone forever.

Python — generating a key pair (using the cryptography library)
from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import serialization # Generate a private key using the elliptic curve algorithm # (same curve Bitcoin and Ethereum use: secp256k1) private_key = ec.generate_private_key(ec.SECP256K1()) # The public key is derived from the private key mathematically # This is a one-way operation — you cannot get the private key from the public key public_key = private_key.public_key() # Export the private key as bytes (store this securely, never share it) priv_bytes = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.BestAvailableEncryption(b'passphrase') )

Signing Transactions — Proving Without Revealing

When you send a transaction, you sign it with your private key. This creates a digital signature — a unique blob of data that proves you authorised this specific transaction.

Anyone can verify the signature using your public key — confirming it came from you — without ever seeing your private key. It is mathematically impossible to fake a valid signature without the private key.

Python — signing and verifying a transaction
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec transaction = b"Shashank sends 1.5 ETH to Priya" # Sign the transaction with the private key signature = private_key.sign( transaction, ec.ECDSA(hashes.SHA256()) ) # Anyone can verify the signature using only the PUBLIC key try: public_key.verify(signature, transaction, ec.ECDSA(hashes.SHA256())) print("Signature valid — this transaction was signed by the key owner.") except Exception: print("Invalid signature — this transaction was NOT authorised.")

Smart Contracts — Code That Lives on the Blockchain

A smart contract is a program that is stored on the blockchain and runs automatically when certain conditions are met. You can think of it as a vending machine: put in the right input (coins plus your selection), get the guaranteed output (your snack). No human cashier needed. No trust required between parties.

Smart contracts are used for things like: automatically releasing payment to a freelancer once work is verified, running a voting system where results cannot be tampered with, creating tokens or NFTs, and running decentralised exchanges where two parties trade without a middleman.

A Simple Solidity Example

Solidity is the programming language used to write smart contracts for the Ethereum network. It looks a bit like JavaScript and Python mixed together.

Solidity — a simple bank-like smart contract on Ethereum
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SimpleBank { // A mapping is like a dictionary: address => balance mapping(address => uint256) private balances; // payable means this function can receive ETH function deposit() public payable { balances[msg.sender] += msg.value; // msg.sender = the address that called this function // msg.value = the amount of ETH they sent } function withdraw(uint256 amount) public { // require acts like an assertion — reverts the whole transaction if false require(balances[msg.sender] >= amount, "Not enough balance"); balances[msg.sender] -= amount; // Transfer ETH back to the caller payable(msg.sender).transfer(amount); } function getBalance() public view returns (uint256) { return balances[msg.sender]; } } // Once deployed, this contract lives on the blockchain forever. // Anyone can deposit and withdraw — no bank, no intermediary. // The rules are enforced by code, not by trust.
⚠️ Smart contracts are immutable once deployed. If you find a bug after deployment, you cannot patch it. Real production contracts go through multiple audits, testnets and formal verification before deployment. A bug in a smart contract can mean permanently lost funds.

Public vs Private Blockchains

Not all blockchains are open to the public. Enterprises often run private blockchains where participation is controlled.

FeaturePublic (Bitcoin, Ethereum)Private (Hyperledger)
Who can joinAnyoneInvited participants only
Who can read dataEveryonePermitted members only
Consensus speedSlow (10 min per block)Fast (seconds)
Energy useHigh (Proof of Work)Low
DecentralisationFully decentralisedPartially centralised
Use caseCryptocurrency, DeFi, NFTsSupply chain, finance, healthcare

Build a Mini Blockchain in Python

Here is a complete minimal blockchain in Python that ties everything together — block creation, hashing, proof of work and chain validation:

Python — a fully working mini blockchain
import hashlib import json from datetime import datetime class Block: def __init__(self, index, data, previous_hash): self.index = index self.timestamp = datetime.utcnow().isoformat() self.data = data self.previous_hash = previous_hash self.nonce = 0 self.hash = self.compute_hash() def compute_hash(self): content = json.dumps({ 'index': self.index, 'timestamp': self.timestamp, 'data': self.data, 'previous_hash': self.previous_hash, 'nonce': self.nonce }, sort_keys=True) return hashlib.sha256(content.encode()).hexdigest() def mine(self, difficulty): target = '0' * difficulty while not self.compute_hash().startswith(target): self.nonce += 1 self.hash = self.compute_hash() class Blockchain: def __init__(self, difficulty=3): self.chain = [] self.difficulty = difficulty self.add_genesis_block() def add_genesis_block(self): genesis = Block(0, "Genesis Block", "0" * 64) genesis.mine(self.difficulty) self.chain.append(genesis) def add_block(self, data): last_block = self.chain[-1] new_block = Block(len(self.chain), data, last_block.hash) new_block.mine(self.difficulty) self.chain.append(new_block) print(f"Block {new_block.index} added. Hash: {new_block.hash[:16]}...") def is_valid(self): for i in range(1, len(self.chain)): cur = self.chain[i] prev = self.chain[i - 1] if cur.hash != cur.compute_hash(): return False if cur.previous_hash != prev.hash: return False return True # Try it out bc = Blockchain(difficulty=3) bc.add_block("Shashank sends 5 BTC to Priya") bc.add_block("Priya sends 2 BTC to Raj") print(f"Chain valid: {bc.is_valid()}") # True # Tamper with block 1 and recheck bc.chain[1].data = "Shashank sends 0 BTC to Priya" print(f"Chain valid: {bc.is_valid()}") # False — tampering detected

Key Concepts at a Glance

ConceptWhat It DoesSimple Analogy
Hash functionCreates a unique fingerprint of any dataA document's fingerprint
BlockContainer holding data and the previous block's hashA page in a shared notebook
ChainList of blocks where each references the lastPages glued together with special ink
NonceA number adjusted during mining to get a valid hashTurning a combination lock
ConsensusHow all nodes agree on the next valid blockA vote that requires effort to cast
Private keyProves ownership, used to sign transactionsA pen with your unique signature style
Public keyYour address, used to receive and to verify signaturesYour bank account number
Smart contractSelf-executing code stored on the blockchainA vending machine — automatic and trustless

⚡ Key Takeaways
  • A blockchain is a linked list of blocks where each block contains the hash of the previous block. This cryptographic linkage makes it nearly impossible to alter historical records without detection.
  • SHA-256 hashing is the foundation. A hash is a fixed-length fingerprint of data. Changing even one character produces a completely different hash — the avalanche effect.
  • Each block contains an index, timestamp, data, the previous block's hash, a nonce and its own hash. The genesis block is the first block with no predecessor, and its previous_hash is all zeros.
  • Tampering with any block breaks its hash, which breaks the link to the next block, which cascades through every subsequent block. On a live network you would need to outpace all other participants to make this work.
  • Proof of Work requires miners to find a nonce that produces a hash starting with a required number of zeros. It is energy-intensive but battle-tested (Bitcoin). Proof of Stake selects validators based on how much they have staked — far more energy-efficient (Ethereum).
  • Ownership is proved with public-private key pairs. The public key is your address. The private key is your proof of ownership. You sign transactions with your private key and anyone can verify the signature with your public key.
  • Never share your private key. There is no account recovery on a blockchain. Lost private key means lost funds forever.
  • Smart contracts are programs deployed to the blockchain that run automatically when triggered. They are immutable once deployed, so auditing and testing before deployment is critical.
  • Public blockchains (Bitcoin, Ethereum) are open to all and fully decentralised. Private blockchains (Hyperledger) are permissioned, faster and used by enterprises for controlled environments.