Skip to content

What is Blockchain?

💡
Before you start

Python 3 and a terminal. Nothing to install, nothing to connect to. macOS and Linux ship with Python; on Windows install it from python.org and tick “Add python.exe to PATH”. Confirm with python3 --version, which should print something like Python 3.12.3.

The word “immutable” is where most people stop understanding blockchains, because it sounds like a promise somebody made rather than something you can check. In the next twenty minutes you will build a small chain, try to change its history, watch it refuse, and then measure exactly what it would cost to force the change through. No cryptocurrency is involved at any point.

What is a Blockchain?

A blockchain is a distributed digital ledger that records transactions across many computers simultaneously. Instead of a single database controlled by one organization, a blockchain spreads identical copies of its data across a network of independent participants called nodes.

Think of it like a shared notebook that thousands of people each hold a copy of. Every time someone writes a new entry, every copy updates at once. No single person can erase or alter past entries because everyone else would immediately notice the discrepancy.

How Blocks Work

A blockchain is literally a chain of blocks. Each block contains:

  • A list of transactions that occurred since the last block
  • A timestamp recording when the block was created
  • A reference to the previous block (called a hash pointer)
  • A unique fingerprint of the block itself (its own hash)

Because each block references the previous one, they form an unbroken chain stretching back to the very first block, known as the genesis block. This chain structure is what makes the data tamper-resistant.

Hashing: The Digital Fingerprint

A hash is a fixed-length string of characters generated by running data through a mathematical function. Hashing is central to blockchain security.

Deterministic The same input always produces the same hash output. Change even one character and the hash changes completely.
One-way You cannot reverse a hash to recover the original data. You can only verify by re-hashing the input and comparing.
Collision-resistant It is computationally infeasible to find two different inputs that produce the same hash.

Because each block contains the hash of the previous block, changing any past transaction would alter that block's hash, which would break the reference in the next block, and the next, and so on. An attacker would need to recalculate every block in the chain to make a forgery look valid.

Decentralization vs Centralization

Traditional systems are centralized: a bank stores your balance in its database, and you trust that bank to maintain accurate records. If the bank's database is compromised, your data is at risk.

Blockchains are decentralized: thousands of independent nodes each store a full copy of the ledger. There is no single point of failure and no single entity to trust or attack.

💡
Decentralized does not mean anonymous

Most blockchains are pseudonymous, not anonymous. Transactions are publicly visible and linked to addresses. With enough analysis, identities can sometimes be traced.

Consensus Mechanisms

For a decentralized network to agree on which transactions are valid, it needs a consensus mechanism — a set of rules that all participants follow to reach agreement without a central authority.

Proof of Work (PoW) Miners compete to solve a computationally difficult puzzle. The first to solve it gets to add the next block and earn a reward. Used by Bitcoin. Extremely energy-intensive but battle-tested since 2009.
Proof of Stake (PoS) Validators lock up (stake) their own cryptocurrency as collateral. They are selected to create blocks based on the amount staked. Dishonest validators lose their stake. Used by Ethereum since 2022. Far more energy-efficient than PoW.
Delegated Proof of Stake (DPoS) Token holders vote for a small number of delegates who validate transactions on their behalf. Faster than PoW and PoS but more centralized.

Immutability: Why It Matters

Once a transaction is confirmed and added to the blockchain, it becomes practically impossible to alter. This property is called immutability, and it has important security implications:

  • Transactions are final — there is no "undo" button. If you send cryptocurrency to the wrong address, there is no bank to call for a reversal.
  • History is auditable — anyone can verify the complete transaction history back to the genesis block.
  • Fraud is detectable — any attempt to alter past records would be immediately visible to all nodes.
⚠️
Immutability is a double-edged sword

The same property that prevents fraud also means mistakes are permanent. A transaction sent to the wrong address or a smart contract with a bug cannot be easily corrected. Always double-check before confirming any transaction.

Why Blockchain Matters for Security

From a cybersecurity perspective, blockchain introduces both strengths and new challenges:

  • No single point of failure — compromising one node does not compromise the network
  • Transparent and auditable — public blockchains allow anyone to verify transactions
  • Cryptographically secured — hashing and digital signatures protect data integrity
  • New attack surface — smart contract vulnerabilities, 51% attacks, and social engineering targeting private keys represent new categories of risk
  • Irreversible transactions — stolen funds are extremely difficult to recover

Now Build a Blockchain and Try to Cheat It, in Five Steps

A blockchain is about forty lines of code, and the useful understanding comes from attacking it rather than reading about it. In the next twenty minutes you will build a three-block chain, alter its history and get caught, cover your tracks and get caught by the next block, and finally measure the work that separates “difficult to change” from “impossible to change”. Every number below came from running these files.

1
Write the chain and its verifier

Go: open a terminal in a folder you can write to, e.g. cd ~/Desktop (Windows: cd %USERPROFILE%\Desktop).

Do: save this as chain.py. It prints nothing on its own. Notice the one idea in it: each block records the hash of the block before it.

import hashlib, json

def block_hash(block):
    return hashlib.sha256(json.dumps(block, sort_keys=True).encode()).hexdigest()

def make_chain(payments):
    chain, previous = [], "0" * 64
    for height, payment in enumerate(payments):
        block = {"height": height, "payment": payment, "previous": previous, "nonce": 0}
        block["hash"] = block_hash({k: v for k, v in block.items() if k != "hash"})
        previous = block["hash"]
        chain.append(block)
    return chain

def check(chain):
    previous = "0" * 64
    for block in chain:
        body = {k: v for k, v in block.items() if k != "hash"}
        if block_hash(body) != block["hash"]:
            return f"block {block['height']} has been altered"
        if block["previous"] != previous:
            return f"block {block['height']} does not follow block {block['height'] - 1}"
        previous = block["hash"]
    return "the whole chain verifies"

You should see: nothing. python3 chain.py should return you to the prompt silently, which means the file parses.

If not: IndentationError means the loop bodies lost their indent. If json is reported as undefined, the import line is missing its second name — it imports both hashlib and json.

2
Build three blocks and verify them

Go: same folder.

Do: save this as build.py and run python3 build.py.

from chain import make_chain, check

chain = make_chain(["alice pays bob 5", "bob pays carol 2", "carol pays dan 1"])
for block in chain:
    print(f"block {block['height']}: {block['payment']:20s} hash {block['hash'][:16]}...")
print()
print(check(chain))

You should see: three linked blocks and a clean verdict:

block 0: alice pays bob 5     hash 4aab0bb5b82fb69f...
block 1: bob pays carol 2     hash 61355760bafc404b...
block 2: carol pays dan 1     hash e25a4b5a1f463847...

the whole chain verifies

Those hashes are not identifiers assigned by anybody — they are computed from the block’s contents. Change a single character of a payment and the hash becomes an entirely different number, which is the property the rest of this rests on.

If not: ModuleNotFoundError: No module named 'chain' means the two files are not in the same folder. Different hashes from those above mean a payment string differs; they must match character for character, including the spaces.

3
Rewrite history and get caught

Go: same folder. Give yourself 500 coins instead of 5.

Do: save this as tamper.py and run it.

from chain import make_chain, check

chain = make_chain(["alice pays bob 5", "bob pays carol 2", "carol pays dan 1"])
chain[0]["payment"] = "alice pays bob 500"        # edit the history
print("after editing block 0:", check(chain))

You should see: the edit named immediately:

after editing block 0: block 0 has been altered

The block’s stored hash no longer matches its contents. Nobody needed a backup, a copy of the original, or a trusted record to notice — the block carries its own evidence.

If not: if it still says the chain verifies, the edit was applied to a copy — chain[0]["payment"] = ... must modify the list you then check.

4
Cover your tracks, and get caught by the next block

Go: same folder. Obvious next move: recompute the altered block’s hash so it matches again.

Do: save this as cover.py and run it.

from chain import make_chain, check, block_hash

chain = make_chain(["alice pays bob 5", "bob pays carol 2", "carol pays dan 1"])
chain[0]["payment"] = "alice pays bob 500"
body = {k: v for k, v in chain[0].items() if k != "hash"}
chain[0]["hash"] = block_hash(body)               # patch up the block's own hash
print("after fixing block 0's hash:", check(chain))

You should see: the failure move one block along:

after fixing block 0's hash: block 1 does not follow block 0

This is the chain in blockchain. Block 1 recorded block 0’s original hash, so repairing block 0 breaks its link to block 1 — and repairing block 1 would break block 2, and so on to the end. One edit forces you to rebuild every block that came after it. With no cost attached to rebuilding, that would still be easy; the next step is where the cost comes from.

If not: if it now reports the whole chain verifies, the body dictionary still includes the old hash key — the comprehension must exclude it.

5
Measure what makes rebuilding expensive

Go: same folder. Proof of work is a rule that a block only counts if its hash starts with a set number of zeros — which can only be found by guessing.

Do: save this as mine.py and run it. It gets slower with each line; that is the point.

import hashlib, time

def mine(data, zeros):
    start, nonce = time.time(), 0
    while True:
        h = hashlib.sha256(f"{data}{nonce}".encode()).hexdigest()
        if h.startswith("0" * zeros):
            return nonce, h, time.time() - start
        nonce += 1

for zeros in (1, 2, 3, 4, 5):
    nonce, h, secs = mine("block 0", zeros)
    print(f"{zeros} leading zero(s): {nonce:>9,} tries, {secs:>6.2f}s, hash {h[:20]}...")

You should see: each extra zero costing roughly sixteen times more work. The try counts are fixed; the times depend on your machine:

1 leading zero(s):        73 tries,   0.00s, hash 0bed7867503a98f7ef05...
2 leading zero(s):       148 tries,   0.00s, hash 0031abb64cd75b389a18...
3 leading zero(s):     3,209 tries,   0.00s, hash 0003497b0012eab4f7af...
4 leading zero(s):   113,511 tries,   0.08s, hash 0000258fb704df77bebb...
5 leading zero(s):   645,488 tries,   0.39s, hash 000005b0ed7319bf3102...

Now put steps 4 and 5 together. Changing one old payment means re-mining that block and every block after it, at this cost per block — while the honest network keeps adding new blocks you also have to catch up on. Bitcoin’s real difficulty is vastly beyond five zeros, which is what turns “you would have to redo the work” into “nobody can”. Immutability is not a promise; it is a bill.

If not: if the 5-zero line takes minutes, your machine is simply slower — the try count should still be 645,488, because the search is deterministic. If it never finishes, the nonce += 1 line is outside the loop.

🎉
Check yourself before moving on

Without scrolling up: someone tells you a blockchain is safe because “the data is encrypted”. Using what you just built, correct them in one sentence — and say what actually protects the history. Answer: nothing in a public blockchain is encrypted at all; every payment in your chain was readable plain text, and on Bitcoin or TON anyone can read every transaction ever made. What protects the history is hashing plus cost: each block commits to the one before it, so altering anything invalidates every block that follows, and the work needed to rebuild them is more than an attacker can afford. Confidentiality and integrity are different properties, and a blockchain provides the second one.

Now do it without the page: add a fourth payment to build.py, then write a version of tamper.py that edits the last block instead of the first, and predict what check will say before you run it. Then answer the question that follows: if the newest block is the cheapest to rewrite, why does every exchange make you wait for several confirmations before crediting a deposit?

Summary

In this tutorial, you learned:

  • A blockchain is a distributed ledger spread across many independent nodes
  • Blocks are chained together using cryptographic hashes, making tampering evident
  • Consensus mechanisms like Proof of Work and Proof of Stake allow networks to agree without a central authority
  • Immutability makes transactions permanent and auditable but also irreversible
  • Blockchain creates new security strengths and new categories of risk
🎉
You now understand blockchain fundamentals!

With this foundation, you are ready to learn how cryptocurrencies use blockchain technology to function as digital money.