Skip to content

Latest commit

Β 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

β‚Ώ PyChain β€” Python Blockchain from Scratch

A fully functional blockchain implementation in pure Python, featuring Proof of Work mining, RSA cryptographic wallets, transaction signing & verification, balance tracking, tamper detection, an interactive CLI, and a full unit test suite.


πŸ“‹ Table of Contents


✨ Features

Feature Details
SHA-256 Hashing Every block is cryptographically sealed with SHA-256
Proof of Work Adjustable mining difficulty (default: 4 leading zeros)
RSA Wallets 2048-bit RSA key-pairs; address derived from public key
Transaction Signing RSA-PSS signatures prevent forgery
Balance Tracking Computed by replaying the entire chain β€” no central DB
Tamper Detection Any modification to a mined block breaks all subsequent hashes
Chain Persistence Chain saved to / loaded from JSON automatically
Interactive CLI Full REPL: create wallets, send coins, mine, inspect chain
38 Unit Tests Full coverage of Block, Blockchain, and Wallet classes

πŸ“ Project Structure

pychain/
β”œβ”€β”€ blockchain/
β”‚   β”œβ”€β”€ __init__.py          # Package exports
β”‚   β”œβ”€β”€ block.py             # Block class β€” hashing, serialisation
β”‚   └── blockchain.py        # Blockchain class β€” PoW, transactions, validation
β”œβ”€β”€ wallet/
β”‚   β”œβ”€β”€ __init__.py          # Package exports
β”‚   └── wallet.py            # RSA wallet β€” key-gen, sign, verify, save/load
β”œβ”€β”€ cli/
β”‚   └── cli.py               # Interactive command-line interface
β”œβ”€β”€ tests/
β”‚   └── test_blockchain.py   # 38 unit tests (pytest)
β”œβ”€β”€ demo.py                  # End-to-end scripted demonstration
β”œβ”€β”€ requirements.txt         # Python dependencies
└── README.md                # This file

πŸ”— How a Blockchain Works

Genesis Block          Block #1                Block #2
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ index: 0    β”‚        β”‚ index: 1    β”‚        β”‚ index: 2    β”‚
β”‚ prev: 0000… │◄───────│ prev: a3f9… │◄───────│ prev: 0000… β”‚
β”‚ txns: []    β”‚        β”‚ txns: [...]  β”‚        β”‚ txns: [...]  β”‚
β”‚ nonce: 0    β”‚        β”‚ nonce: 132k  β”‚        β”‚ nonce: 33k   β”‚
β”‚ hash: a3f9… β”‚        β”‚ hash: 0000… β”‚        β”‚ hash: 0000… β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β–²                      β–²
                        Must start with         Must start with
                        "0000" (PoW)            "0000" (PoW)

Why is it secure?

  • Changing Block #1's data changes its hash β†’ Block #2's previous_hash no longer matches β†’ the chain is broken.
  • An attacker would need to re-mine Block #1 and every block after it, faster than the honest network β€” practically impossible.

πŸš€ Quick Start

1. Install dependencies

pip install -r requirements.txt

2. Run the demo

python demo.py

3. Launch the interactive CLI

python cli/cli.py

🎬 Running the Demo

demo.py walks through the complete lifecycle automatically:

β‚Ώ  PyChain β€” Full Blockchain Demo

1. INITIALISING BLOCKCHAIN
   Chain initialised with 1 block(s) (genesis only).

2. CREATING WALLETS
   Alice   : 6d16867d45f3fbf00f811fcb69d29d29344c001b
   Bob     : 77d45d388a254db85a12bf3f4762eebe7f8c0134

3. FUNDING ALICE (COINBASE + MINE)
   ⛏  Mining block #1 (difficulty=4)…
   βœ…  Block #1 mined! Nonce=132790, Hash=0000af21c08af563…

4. BALANCES AFTER FUNDING
   Alice   : 200.0000 coins
   Bob     :  50.0000 coins

5. ALICE SENDS 30 COINS TO BOB
   Signature valid: True

...

12. TAMPER DETECTION DEMO
   ⚠  Attempting to tamper with Block #1…
   ❌  Block #1: stored hash doesn't match recomputed hash.
   πŸ›‘  TAMPER DETECTED!

πŸ’» Interactive CLI

Start the REPL:

python cli/cli.py

Available Commands

Command Description
new_wallet Generate a new RSA wallet
load_wallet Load a wallet from a .json file
balance Check the confirmed balance of any address
send Queue a signed transaction from the active wallet
mine Mine all pending transactions into a new block
chain Print all blocks in the chain
validate Verify the entire chain's cryptographic integrity
history Show transaction history for an address
balances Show all confirmed account balances
pending List transactions in the mempool
help Show the command menu
exit Quit PyChain

Example Session

PyChain [no wallet] > new_wallet
  βœ…  New wallet created!
  Address : 6d16867d45f3fbf00f811fcb69d29d2

PyChain [6d16867d…] > mine
  ⛏  Mining block #1 (difficulty=4)…
  βœ…  Block #1 mined! Nonce=132790

PyChain [6d16867d…] > balance
  β€Ί Wallet address: 6d16867d45f3fbf00f811fcb69d29d2
  Balance : 10.00000000 coins

πŸ§ͺ Running Tests

# Run all 38 tests with verbose output
python -m pytest tests/test_blockchain.py -v

# Run a specific test class
python -m pytest tests/test_blockchain.py::TestWallet -v

# Run a single test
python -m pytest tests/test_blockchain.py::TestBlockchain::test_tampered_transaction_fails_validation -v

Test coverage:

TestBlock        (4 tests)  β€” hash correctness, serialisation, repr
TestBlockchain  (24 tests)  β€” genesis, PoW, transactions, mining,
                              balances, validation, persistence, history
TestWallet      (10 tests)  β€” key generation, signing, verification,
                              save/load, PEM export

All 38 tests pass in ~25 seconds (mining is intentionally slow by design).


πŸ“š Core Concepts Explained

SHA-256 Hash

import hashlib, json

data = {"index": 1, "nonce": 42, "transactions": [...]}
digest = hashlib.sha256(
    json.dumps(data, sort_keys=True).encode("utf-8")
).hexdigest()
# β†’ "0000af21c08af563c531e52b..."
  • Same input always produces the same hash (deterministic).
  • Changing even 1 character changes the entire hash (avalanche effect).
  • You cannot reverse a hash to get the original data (one-way function).

Proof of Work

target = "0000"          # difficulty = 4
nonce  = 0

while not block.compute_hash().startswith(target):
    nonce += 1           # Try billions of nonces until hash starts with "0000"

# On average this takes ~65,536 attempts for difficulty=4

Mining is hard (CPU-intensive), but verification is instant β€” anyone can check that hash.startswith("0000") in one step.

RSA Signature

# Sender signs (proves ownership of the private key)
signature = private_key.sign(transaction_bytes, PSS_padding, SHA256)

# Anyone can verify using only the public key
public_key.verify(signature, transaction_bytes, PSS_padding, SHA256)
# β†’ Raises InvalidSignature if tampered

Only the true owner of the private key can produce a valid signature. This prevents anyone from spending coins from an address they don't control.

Balance Calculation

Balances are not stored β€” they are computed on demand by replaying every transaction in the chain from the beginning:

balance = 0.0
for block in chain[1:]:          # Skip genesis
    for tx in block.transactions:
        if tx["recipient"] == address:
            balance += tx["amount"]
        if tx["sender"] == address:
            balance -= tx["amount"] + tx["fee"]

This is the same approach Bitcoin uses (UTXO model is a more efficient variant).


πŸ“– API Reference

Block(index, transactions, previous_hash, nonce=0)

Method Returns Description
compute_hash() str SHA-256 hash of all block fields
to_dict() dict Serialisable plain dictionary

Blockchain(chain_file="chain.json")

Method Returns Description
add_transaction(sender, recipient, amount, fee, note) dict Validate and add to mempool
mine_pending_transactions(miner_address) Block or None Run PoW and append new block
get_balance(address) float Replay chain to compute balance
get_all_balances() dict All address β†’ balance pairs
is_chain_valid() bool Verify hash integrity across chain
get_transaction_history(address) list All confirmed txns for address
save_chain() β€” Persist chain to JSON file
print_chain() β€” Pretty-print all blocks

Wallet()

Method Returns Description
sign_transaction(tx_dict) bytes RSA-PSS signature
verify_signature(pub_pem, tx, sig) bool Static method β€” verify signature
get_public_key_pem() str PEM-encoded public key
get_private_key_pem(password) str PEM-encoded private key
save_to_file(path, password) β€” Save wallet as JSON
load_from_file(path, password) Wallet Class method β€” restore wallet

βš™οΈ Configuration

Edit constants in blockchain/blockchain.py:

MINING_DIFFICULTY = 4    # Number of leading zeros required in block hash
                          # Higher = harder mining, more security
                          # Typical values: 3 (fast) β†’ 6 (slow/secure)

MINING_REWARD = 10.0     # Coins awarded to the miner per mined block

PyChain is an educational project demonstrating blockchain fundamentals. It is a single-node implementation. It does not include peer-to-peer networking, a distributed consensus protocol, or production-grade security hardening. Do not use it to store or transfer real assets.

About

Project created with the help of Pychain built from scratch demonstrates the core mechanics behind cryptocurrencies like Bitcoin. It implements SHA-256 block hashing, Proof of Work mining, RSA cryptographic wallets with transaction signing, balance tracking by chain replay, and tamper detection.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages