A minimal, from-scratch Blockchain implementation in Python demonstrating:
- SHA-256 based block hashing
- Proof-of-Work (PoW) mining with adjustable difficulty
- Chain validation
- A simple P2P network demo using Flask nodes (longest-chain consensus)
basic-blockchain/
├── block.py # Block class + hash computation
├── blockchain.py # Blockchain class: PoW, validation, consensus
├── app.py # Flask REST API node for P2P networking
├── test_local.py # Standalone demo without networking
├── requirements.txt
└── README.md
git clone https://github.com/vedant-4747/basic-blockchain.git
cd basic-blockchain
python -m venv venv
source venv/bin/activate # venv\Scripts\activate on Windows
pip install -r requirements.txtpython test_local.pyThis creates the genesis block, adds transactions, mines two blocks with PoW, and prints the full chain plus a validity check.
Start two or more nodes in separate terminals:
python app.py 8000
python app.py 8001Register node 8001 with node 8000 (this syncs the chain too):
curl -X POST http://127.0.0.1:8001/register_with \
-H "Content-Type: application/json" \
-d '{"node_address": "http://127.0.0.1:8000/"}'Submit a transaction to node 8000:
curl -X POST http://127.0.0.1:8000/new_transaction \
-H "Content-Type: application/json" \
-d '{"author": "Vedant", "content": "Send 5 coins to Asha"}'Mine it on node 8000 (this broadcasts the new block to registered peers):
curl http://127.0.0.1:8000/mineCheck the chain on node 8001 — it should now include the newly mined block:
curl http://127.0.0.1:8001/chainEvery block's contents (index, transactions, previous hash, timestamp, nonce) are serialized to JSON and hashed with SHA-256 to produce a unique fingerprint. Changing any field changes the hash completely.
difficulty = 4 means a valid block hash must start with four zeros. The
nonce is incremented repeatedly until this condition is met — this is the
"work" that secures the chain against tampering.
is_chain_valid() walks the chain and checks that each block's
previous_hash matches the prior block's hash, and that each block's stored
hash actually satisfies the PoW target.
Each Flask node keeps its own copy of the chain and a set of peer URLs.
When a node mines a block, it POSTs that block to every peer's /add_block
endpoint. If a node discovers a longer valid chain from a peer, it adopts it
(longest-chain rule), which is how the network resolves conflicts.
- Digital signatures for transactions (public/private key pairs)
- Wallet balances and UTXO tracking
- Dynamic difficulty adjustment based on block time
- A simple web UI to visualize the chain