In Part 1, we built a basic blockchain with blocks, hashing, and chain validation. In this second part, we add Proof of Work mining and a transaction system.
Proof of Work
Proof of Work requires miners to find a hash that meets certain criteria (starts with N zeros). This computational work makes it expensive to rewrite history.
Adding Mining to the Block
import hashlib, json
from datetime import datetime
class Block:
def __init__(self, index, transactions, previous_hash):
self.index = index
self.timestamp = datetime.now().isoformat()
self.transactions = transactions
self.previous_hash = previous_hash
self.nonce = 0
self.hash = self.calculate_hash()
def calculate_hash(self):
block_string = json.dumps({
'index': self.index, 'timestamp': self.timestamp,
'transactions': self.transactions,
'previous_hash': self.previous_hash, 'nonce': self.nonce
}, sort_keys=True)
return hashlib.sha256(block_string.encode()).hexdigest()
def mine_block(self, difficulty):
target = "0" * difficulty
while not self.hash.startswith(target):
self.nonce += 1
self.hash = self.calculate_hash()
print(f"Mined! Nonce: {self.nonce}, Hash: {self.hash}")
Updated Blockchain with Transactions
class Blockchain:
def __init__(self, difficulty=4):
self.chain = [Block(0, [], "0")]
self.difficulty = difficulty
self.pending_transactions = []
self.mining_reward = 10
def add_transaction(self, sender, recipient, amount):
self.pending_transactions.append({
'sender': sender, 'recipient': recipient, 'amount': amount
})
def mine_pending_transactions(self, miner_address):
block = Block(len(self.chain), self.pending_transactions, self.chain[-1].hash)
block.mine_block(self.difficulty)
self.chain.append(block)
self.pending_transactions = [{'sender': 'REWARD', 'recipient': miner_address, 'amount': self.mining_reward}]
def get_balance(self, address):
balance = 0
for block in self.chain:
for tx in block.transactions:
if tx['recipient'] == address: balance += tx['amount']
if tx['sender'] == address: balance -= tx['amount']
return balance
Usage Example
bc = Blockchain(difficulty=4)
bc.add_transaction("Alice", "Bob", 50)
bc.add_transaction("Bob", "Charlie", 25)
print("Mining...")
bc.mine_pending_transactions("Miner1")
print(f"Alice: {bc.get_balance('Alice')}")
print(f"Miner1: {bc.get_balance('Miner1')}")
Key Concepts Learned
- Mining finds a valid nonce that produces a hash meeting the difficulty target
- The mining reward creates an incentive for miners to secure the network
- Balances are calculated by scanning all transactions (UTXO-style)
Real blockchains add peer-to-peer networking, Merkle trees, digital signatures, and dynamic difficulty adjustment on top of these fundamentals.