Key takeaways
- There is no single Python blockchain library: hashlib, web3.py, Ape and pycoingecko each do a different job.
- You can build a working toy chain in about 60 lines of standard-library Python, and it is the fastest way to understand hashing, linking, proof of work and validation.
- For real networks, web3.py on a testnet is the starting point, with keys kept out of the code.
- Contracts are usually written in Solidity or Vyper. Python tests, deploys, indexes and reports around them.
- Before any of that, check that the product needs a shared ledger at all.
Python is rarely the language a blockchain runs on, and almost always a language people use around one. Developers reach for it to prototype a chain and learn how one works, to test and deploy smart contracts, to read on-chain data into a database, and to build the APIs, reports and back-office tools a blockchain product needs.
This guide covers the Python blockchain libraries people search for and what each one actually does. It then builds a small working chain in plain Python, connects to a real test network with web3.py, and ends with how we’d decide where Python belongs in a fintech product.
Which Python blockchain library should you use?
The right Python blockchain library depends on the job: hashlib for building a chain yourself, web3.py for working with Ethereum-style networks, Ape for testing and deploying contracts, and pycoingecko for market data. Expect to combine two or three of them in one project.
| Library or tool | What it does | Use it when |
|---|---|---|
hashlib (standard library) |
SHA-256 and other hash functions | You are building or teaching a simple chain |
web3.py |
Connects to Ethereum and EVM-compatible nodes: reads blocks, balances and contract state, signs and sends transactions | Your product reads from or writes to a public or private EVM chain |
eth-account |
Creates keys and signs messages and transactions (web3.py uses it underneath) | You manage keys or sign offline |
| Ape | A Python framework to compile, test and deploy smart contracts | You write contracts and want Python tests around them |
| Vyper | A contract language with Python-like syntax that compiles for the Ethereum Virtual Machine | Your team prefers Python-style syntax for contracts |
| Algorand Python | Write Algorand smart contracts in a subset of Python | You build on Algorand |
python-bitcoinlib |
Bitcoin data structures, scripts and transactions | You work with Bitcoin transactions directly |
solana-py and solders |
Python clients for the Solana network | You build on Solana |
pycoingecko |
A wrapper for the CoinGecko API: prices and market data | You need prices for a dashboard or a report, not chain access |
A few names come up in searches more often than they come up in real projects. pyblockchain and pychain are the names of small, mostly educational projects rather than one maintained library. Before you depend on any of them, check the repository: when it was last released, whether issues get answers, and whether its licence suits your product. Brownie, the Python contract framework many older tutorials use, now says in its own README that it is no longer actively maintained, and its maintainers point users to Ape.
Hyperledger Fabric, a framework for permissioned business chains, is often listed as a Python option. Its smart contracts (chaincode) are written in Go, Java or JavaScript, so Python’s role there is the application around the network, not the contracts.
Can you build a blockchain in Python?
Yes: with the standard library alone you can build a working chain of hashed, linked blocks with proof of work and a validity check. The version below is about 60 lines. It is not a network (there are no peers and no consensus between nodes), but it shows exactly what a chain is.
import hashlib
import json
import time
def sha256(data: dict) -> str:
# Sort the keys so the same block always hashes to the same value
encoded = json.dumps(data, sort_keys=True).encode()
return hashlib.sha256(encoded).hexdigest()
class Blockchain:
def __init__(self, difficulty: int = 4):
self.difficulty = difficulty
self.pending = []
self.chain = []
self.add_block(previous_hash="0" * 64) # the genesis block
def add_transaction(self, sender: str, recipient: str, amount: int) -> None:
self.pending.append({"sender": sender, "recipient": recipient, "amount": amount})
def proof_of_work(self, block: dict) -> dict:
# Try nonces until the block's hash starts with `difficulty` zeros
block["nonce"] = 0
while not sha256(block).startswith("0" * self.difficulty):
block["nonce"] += 1
return block
def add_block(self, previous_hash: str = "") -> dict:
block = {
"index": len(self.chain),
"timestamp": time.time(),
"transactions": self.pending,
"previous_hash": previous_hash or sha256(self.chain[-1]),
}
self.chain.append(self.proof_of_work(block))
self.pending = []
return block
def is_valid(self) -> bool:
for prev, block in zip(self.chain, self.chain[1:]):
if block["previous_hash"] != sha256(prev):
return False # a link in the chain is broken
if not sha256(block).startswith("0" * self.difficulty):
return False # the block skipped its proof of work
return True
chain = Blockchain()
chain.add_transaction("asha", "ravi", 25)
chain.add_block()
print(len(chain.chain), chain.is_valid()) # 2 True
chain.chain[1]["transactions"][0]["amount"] = 2500 # tamper with history
print(chain.is_valid()) # False
Run it with python3 chain.py. It prints 2 True, then False once a past transaction is changed. It runs on Python 3.9 and later with nothing to install.
How the code works
Four ideas carry the whole thing:
- Hashing.
sha256()turns a block into a fixed-length fingerprint. Change one character of the block and the fingerprint changes completely. Sorting the JSON keys keeps the fingerprint stable for the same data. - Linking. Each block stores the hash of the block before it in
previous_hash. Editing an old block changes its hash, which no longer matches the link stored in the next block. - Proof of work.
proof_of_work()keeps changing thenonceuntil the block’s hash starts with a set number of zeros. Finding that nonce takes many attempts, and checking it takes one. Raisedifficultyfrom 4 to 5 and mining takes roughly 16 times longer. - Validation.
is_valid()walks the chain and checks both rules for every block. In the example, the tampered block fails the proof-of-work check, because its new hash almost certainly no longer starts with four zeros. In a longer chain, an attacker who re-mined the tampered block would still be caught, because the link check on the next block would fail.
What a toy chain leaves out
A real network adds the parts that make a chain trustworthy between strangers.
You don’t need to build these yourself for a product. Node software for the major networks already exists, written in languages such as Go, Rust, C++ and Java. Python’s job is to talk to it.
How do you connect Python to a real blockchain?
You connect Python to a real blockchain through web3.py and an RPC endpoint: a URL for a node you run or rent from a node provider. Start on a test network such as Sepolia, where the currency has no value and you can get test funds from a public faucet.
Install it with pip install web3. The examples below use the web3.py version 7 names; older tutorials use version 6 names such as rawTransaction.
import os
from decimal import Decimal
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(os.environ["SEPOLIA_RPC_URL"]))
print(w3.is_connected(), w3.eth.block_number)
address = Web3.to_checksum_address(os.environ["MY_ADDRESS"])
balance = w3.eth.get_balance(address)
print(w3.from_wei(balance, "ether"), "test ETH")
Read a smart contract
To read a contract you need its address and its ABI, the description of its functions. This reads a token balance from any ERC-20 token contract, using only the two functions it needs:
ERC20_ABI = [
{"name": "balanceOf", "type": "function", "stateMutability": "view",
"inputs": [{"name": "owner", "type": "address"}],
"outputs": [{"name": "", "type": "uint256"}]},
{"name": "decimals", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{"name": "", "type": "uint8"}]},
]
token = w3.eth.contract(
address=Web3.to_checksum_address(os.environ["TOKEN_ADDRESS"]), abi=ERC20_ABI
)
raw = token.functions.balanceOf(address).call()
print(Decimal(raw) / 10 ** token.functions.decimals().call())
Send a transaction
Sending changes state, so it needs a signature from your private key and a fee. Keep the key in an environment variable or a secrets manager, never in the code or the repository.
account = w3.eth.account.from_key(os.environ["PRIVATE_KEY"])
base_fee = w3.eth.get_block("latest")["baseFeePerGas"]
tx = {
"to": Web3.to_checksum_address(os.environ["RECIPIENT"]),
"value": w3.to_wei(Decimal("0.001"), "ether"),
"nonce": w3.eth.get_transaction_count(account.address),
"gas": 21000, # a plain transfer
"maxPriorityFeePerGas": w3.to_wei(1, "gwei"),
"maxFeePerGas": base_fee * 2 + w3.to_wei(1, "gwei"),
"chainId": 11155111, # Sepolia
}
signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(receipt.status) # 1 means it succeeded
The same pattern covers contract writes: build the call with token.functions.transfer(to, amount).build_transaction({...}), sign it and send it.
Read market data with pycoingecko
When you need prices rather than chain data, pycoingecko is the short route. It calls CoinGecko’s API, so check their current terms and rate limits before you depend on it in a product.
from pycoingecko import CoinGeckoAPI
cg = CoinGeckoAPI() # or CoinGeckoAPI(demo_api_key="...") with a free Demo key
print(cg.get_price(ids="bitcoin,ethereum", vs_currencies="inr"))
Is Python good for smart contracts?
Python is not the usual language for the contract itself, but it is very good for everything around it. On Ethereum and other EVM chains, contracts are mostly written in Solidity, or in Vyper, which borrows Python’s syntax and keeps the language small on purpose. Algorand is one exception: its tooling compiles a subset of Python into contract code.
Where Python earns its place is the work around the contract:
- Testing. Ape runs contract tests written in Python against a local chain, so you can test edge cases (a zero transfer, a missing approval, a paused contract) before anything is deployed.
- Deployment scripts. The same scripts deploy to a testnet first and a main network later, with the addresses recorded.
- Monitoring. A Python worker watches the contract’s events and alerts someone when something unusual happens.
Where Python fits in a blockchain product
Most of a blockchain product is ordinary software, and much of it suits Python well. These five jobs are where it fits best.
Python’s limit is raw speed in the node itself: validating thousands of signatures a second or running a consensus protocol. Those parts live in the node software, and you use them rather than rebuild them. For a broader view of where Python is the right tool, see when to use Python.
Building a fintech product?
Our first question would be whether it needs a shared ledger at all. Talk it through with us before the design is fixed.
How we’d build it for a fintech product
Our first question would be whether the product needs a shared ledger at all. A blockchain earns its cost when several parties who don’t fully trust one operator must share one record that none of them can quietly rewrite. When one company runs the system, a normal database with an append-only history table, signed entries and regular backups usually does the same job faster and cheaper. Our post on whether your business needs a blockchain covers that decision in more depth.
If a chain does fit, here is how we’d approach the build, in six steps.
For more on regulated financial products, see our fintech app development page. If you need people to build the Python side, you can hire Python developers.
