Skip to content

swoet/py-blockchain-tutorial

Repository files navigation

🔗 Python Blockchain Tutorial

    ╔═══════════════════════════════════════════════════════════╗
    ║                                                           ║
    ║     ██████╗ ██╗      ██████╗  ██████╗██╗  ██╗           ║
    ║     ██╔══██╗██║     ██╔═══██╗██╔════╝██║ ██╔╝           ║
    ║     ██████╔╝██║     ██║   ██║██║     █████╔╝            ║
    ║     ██╔══██╗██║     ██║   ██║██║     ██╔═██╗            ║
    ║     ██████╔╝███████╗╚██████╔╝╚██████╗██║  ██╗           ║
    ║     ╚═════╝ ╚══════╝ ╚═════╝  ╚═════╝╚═╝  ╚═╝           ║
    ║                                                           ║
    ║        ██████╗██╗  ██╗ █████╗ ██╗███╗   ██╗             ║
    ║       ██╔════╝██║  ██║██╔══██╗██║████╗  ██║             ║
    ║       ██║     ███████║███████║██║██╔██╗ ██║             ║
    ║       ██║     ██╔══██║██╔══██║██║██║╚██╗██║             ║
    ║       ╚██████╗██║  ██║██║  ██║██║██║ ╚████║             ║
    ║        ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝             ║
    ║                                                           ║
    ╚═══════════════════════════════════════════════════════════╝

A production-ready FastAPI blockchain with PoW, Consensus, and Multi-Node Docker

Python FastAPI Docker Tests Type Checked


🎯 Overview

A lightweight, educational blockchain framework built with FastAPI, featuring:

  • ⛏️ Proof-of-Work mining with adjustable difficulty
  • 🔗 SHA-256 cryptographic block hashing
  • 🌐 Multi-node peer-to-peer consensus
  • 📡 RESTful + OpenAPI with auto-generated docs
  • 🎨 Real-time HTMX/Tailwind UI dashboard
  • 🐳 Multi-node Docker orchestration
  • ✅ Full Pydantic validation and type safety

Perfect for learning how blockchains work under the hood or as a foundation for custom distributed ledger experiments.


🏗️ 3D Architecture

                    ┌──────────────────────────────────────────┐
                    │         FastAPI Application              │
                    │    (Uvicorn ASGI Server - Port 5000)     │
                    └──────────────┬───────────────────────────┘
                                   │
                  ┌────────────────┼────────────────┐
                  │                │                │
                  ▼                ▼                ▼
        ┌─────────────────┐ ┌───────────┐ ┌─────────────────┐
        │   UI Routes     │ │ API Routes│ │ Legacy Routes   │
        │ (HTMX/Jinja2)   │ │ (/api/*)  │ │ (/mine, /chain) │
        └────────┬─────────┘ └─────┬─────┘ └────────┬────────┘
                 │                 │                 │
                 └─────────────────┼─────────────────┘
                                   │
                        ┌──────────▼──────────┐
                        │   Blockchain Core   │
                        │  (In-Memory State)  │
                        └──────────┬──────────┘
                                   │
              ┌────────────────────┼────────────────────┐
              │                    │                    │
              ▼                    ▼                    ▼
    ┌─────────────────┐  ┌─────────────────┐  ┌────────────────┐
    │   Block Chain   │  │    Mempool      │  │  Peer Nodes    │
    │ [Block₀, B₁...] │  │ [Pending Txs]   │  │ {node1, node2} │
    └─────────────────┘  └─────────────────┘  └────────────────┘
              │                    │                    │
              │                    │                    │
              ▼                    ▼                    ▼
    ┌─────────────────┐  ┌─────────────────┐  ┌────────────────┐
    │   PoW Mining    │  │  Tx Validation  │  │   Consensus    │
    │ (SHA-256 hash)  │  │ (Pydantic)      │  │ (Longest chain)│
    └─────────────────┘  └─────────────────┘  └────────────────┘

Multi-Node Network Topology

         Internet/Host Machine (localhost)
                    │
     ┌──────────────┼──────────────┐
     │              │              │
Port 5000      Port 5001      Port 5002
     │              │              │
     ▼              ▼              ▼
┌─────────┐    ┌─────────┐    ┌─────────┐
│ Node 1  │◄──►│ Node 2  │◄──►│ Node 3  │
│ (node1) │    │ (node2) │    │ (node3) │
└────┬────┘    └────┬────┘    └────┬────┘
     │              │              │
     └──────────────┼──────────────┘
                    │
            Docker Bridge Network
             (blockchain-net)
                    │
         Auto-registration via PEERS env

📦 Project Structure

py-blockchain-tutorial/
│
├── 📁 app/                      # Core application package
│   ├── __init__.py              # Flask legacy factory (deprecated)
│   ├── api.py                   # 🚀 FastAPI app + all endpoints
│   ├── blockchain.py            # ⛓️  Blockchain logic (PoW, consensus)
│   ├── models.py                # 📋 Pydantic schemas for validation
│   ├── main.py                  # 🎬 Uvicorn entrypoint
│   └── routes.py                # (deprecated, migrated to api.py)
│
├── 📁 templates/                # Jinja2 HTML templates
│   ├── index.html               # 🎨 Main dashboard (HTMX + Tailwind)
│   └── _status.html             # 📊 Live status partial
│
├── 📁 tests/                    # Pytest test suite
│   ├── test_app.py              # ✅ API & integration tests
│   └── requirements.txt         # Test dependencies
│
├── 📁 .github/workflows/        # CI/CD pipelines
│   └── ci.yml                   # GitHub Actions: lint→test→audit
│
├── 🐳 Dockerfile                # Production container image
├── 🐳 docker-compose.yml        # Multi-node orchestration
├── ⚙️  pyproject.toml            # Project metadata + tool configs
├── 🔧 .pre-commit-config.yaml   # Git hooks for quality checks
├── 📄 requirements.txt          # Legacy root deps (use pyproject.toml)
└── 📖 README.md                 # This file

🚀 Quick Start

1️⃣ Local Development (Single Node)

# Install dependencies
pip install -e .[dev]

# Run the server
python -m app.main

# Open in browser
# UI:       http://127.0.0.1:5000
# API docs: http://127.0.0.1:5000/docs
# ReDoc:    http://127.0.0.1:5000/redoc

2️⃣ Multi-Node Demo (Docker)

# Spin up 3 interconnected nodes
docker compose up --build -d

# Access nodes
# Node 1: http://127.0.0.1:5000
# Node 2: http://127.0.0.1:5001
# Node 3: http://127.0.0.1:5002

# Example: Mine a block on node 1
curl http://localhost:5000/mine

# View the chain
curl http://localhost:5000/chain | jq

# Trigger consensus on node 2 (sync from peers)
curl http://localhost:5001/nodes/resolve | jq

# Stop nodes
docker compose down

🎨 UI Dashboard

The live dashboard (powered by HTMX + Tailwind) provides real-time updates, interactive buttons, and toast notifications:

UI Screenshot

Features:

  • 📊 Live status cards (height, difficulty, mempool, last block hash)
  • Add Tx button (green) - adds test transactions to mempool
  • ⛏️ Mine Block button (blue) - mines pending transactions
  • 📦 Recent blocks viewer with auto-refresh
  • 📝 Mempool viewer showing pending transactions
  • 🔔 Toast notifications for success/error feedback
  • 🔄 Auto-refresh every 2-5 seconds

📡 API Endpoints

Modern API (/api/*)

Method Endpoint Description
GET /api/status Chain status + metrics
GET /api/blocks Recent blocks (paginated)
GET /api/mempool Pending transactions
POST /api/tx Submit a transaction
POST /api/mine Mine pending txs into a block

Legacy Endpoints (Tutorial Compatible)

Method Endpoint Description
GET /mine Mine block with reward tx
POST /transactions/new Add transaction (validated)
GET /chain Full chain + length
POST /nodes/register Register peer nodes
GET /nodes/resolve Consensus (longest chain wins)

Interactive Docs


🔬 Example Usage

Mining Workflow

# 1. Add transactions to mempool
curl -X POST http://127.0.0.1:5000/api/tx \
  -H "Content-Type: application/json" \
  -d '{"from": "alice", "to": "bob", "amount": 10}'

curl -X POST http://127.0.0.1:5000/api/tx \
  -H "Content-Type: application/json" \
  -d '{"from": "charlie", "to": "dave", "amount": 5}'

# 2. Check mempool
curl http://127.0.0.1:5000/api/mempool | jq

# 3. Mine a block
curl -X POST http://127.0.0.1:5000/api/mine | jq

# 4. Verify chain
curl http://127.0.0.1:5000/chain | jq '.chain[-1]'

Multi-Node Consensus

# Node 1: Mine several blocks
for i in {1..3}; do
  curl -X POST http://127.0.0.1:5000/api/tx \
    -H "Content-Type: application/json" \
    -d "{\"from\":\"miner\",\"to\":\"user$i\",\"amount\":1}"
  curl http://127.0.0.1:5000/mine
done

# Node 2: Check initial state
curl http://127.0.0.1:5001/chain | jq '.length'
# Output: 1 (genesis only)

# Node 2: Resolve conflicts (sync from node 1)
curl http://127.0.0.1:5001/nodes/resolve | jq

# Node 2: Verify sync
curl http://127.0.0.1:5001/chain | jq '.length'
# Output: 4 (genesis + 3 mined blocks)

🧪 Testing

# Run all tests
pytest

# With coverage
pytest --cov=app

# Type check
mypy app

# Lint & format
ruff check --fix .
ruff format .
black .
isort .

# Security audit
pip-audit

Test Coverage:

  • ✅ Status endpoint
  • ✅ Transaction submission + mining flow
  • ✅ Legacy /mine endpoint
  • ✅ Transaction validation (Pydantic)
  • ✅ Chain retrieval
  • ✅ Node registration
  • ✅ Consensus resolution

🛠️ Technology Stack

┌─────────────────────────────────────────────────────────┐
│  Layer          │  Technology                           │
├─────────────────┼───────────────────────────────────────┤
│  Web Framework  │  FastAPI 0.121+ (ASGI)                │
│  Server         │  Uvicorn (asyncio event loop)         │
│  Validation     │  Pydantic 2.12+                       │
│  Templates      │  Jinja2 3.1+                          │
│  Frontend       │  HTMX 1.9 + Tailwind CSS (CDN)        │
│  Testing        │  Pytest 9.0+, Hypothesis 6.147+       │
│  Type Checking  │  Mypy 1.18+ (strict mode)             │
│  Linting        │  Ruff 0.14+, Black, Isort             │
│  Security       │  Bandit, pip-audit                    │
│  Containerization│ Docker + Docker Compose              │
│  CI/CD          │  GitHub Actions                       │
└─────────────────────────────────────────────────────────┘

🔐 Security Features

  • 🔒 SHA-256 hashing for block integrity
  • Pydantic validation for all inputs
  • 🛡️ Request size limits (FastAPI defaults)
  • 🔍 Dependency auditing via pip-audit
  • 🔐 No secrets in code (env var best practices)
  • 📊 Type safety with mypy strict mode

📊 Block Structure

Block {
    index: int              # Sequential block number
    timestamp: float        # Unix timestamp
    previous_hash: str      # SHA-256 of previous block
    nonce: int              # Proof-of-Work solution
    transactions: [...]     # List of transactions
    hash: str               # SHA-256 of this block
}

Visual Block Chain

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Block 0   │    │   Block 1   │    │   Block 2   │
│  (Genesis)  │◄───│             │◄───│             │
├─────────────┤    ├─────────────┤    ├─────────────┤
│ idx: 0      │    │ idx: 1      │    │ idx: 2      │
│ prev: 000...│    │ prev: abc...│    │ prev: def...│
│ nonce: 0    │    │ nonce: 1234 │    │ nonce: 5678 │
│ txs: [gen]  │    │ txs: [tx1]  │    │ txs: [tx2]  │
│ hash: abc...│    │ hash: def...│    │ hash: ghi...│
└─────────────┘    └─────────────┘    └─────────────┘

⚙️ Configuration

Environment Variables

Variable Description Default
PORT Server port 5000
NODE_ID Unique identifier for this node Random UUID
PEERS Comma-separated peer addresses (empty)

Docker Compose

Nodes auto-register peers via PEERS env:

node1:
  environment:
    - NODE_ID=node1
    - PEERS=blockchain-node2:8000,blockchain-node3:8000

🎓 Learning Path

Beginner

  1. ✅ Run locally and explore the UI
  2. ✅ Submit transactions via /api/tx
  3. ✅ Mine blocks with /api/mine
  4. ✅ Inspect chain structure at /chain

Intermediate

  1. ✅ Study blockchain.py PoW algorithm
  2. ✅ Add custom transaction fields
  3. ✅ Modify mining difficulty
  4. ✅ Run multi-node Docker setup

Advanced

  1. ✅ Implement Merkle tree for transactions
  2. ✅ Add ECDSA signatures (secp256k1)
  3. ✅ Persistent storage (SQLite/LevelDB)
  4. ✅ WebSocket live updates
  5. ✅ UTXO model with double-spend prevention

🤝 Contributing

Contributions welcome! Please:

  1. Fork the repo
  2. Create a feature branch
  3. Run tests + linting: pytest && mypy app && ruff check .
  4. Submit a PR

📝 License

MIT License - feel free to use for learning or commercial projects.


🙏 Acknowledgments

  • Original tutorial inspired by classic blockchain educational resources
  • Built with modern Python best practices (2025)
  • Community feedback and contributions

⭐ Star this repo if you found it helpful!

Made with ❤️ for the blockchain learning community

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published