```python
import hashlib
import json
import time
from typing import List, Dict
import threading
import socket
import sqlite3
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
class Block:
def __init__(self, index, transactions, timestamp, previous_hash):
self.index = index
self.transactions = transactions
self.timestamp = timestamp
self.previous_hash = previous_hash
self.nonce = 0
self.hash = self.calculate_hash()
def calculate_hash(self):
block_string = json.dumps(self.__dict__, sort_keys=True)
return hashlib.sha256(block_string.encode()).hexdigest()
class Blockchain:
def __init__(self):
self.chain = [self.create_genesis_block()]
self.difficulty = 4
self.pending_transactions = []
self.mining_reward = 10
self.nodes = set()
self.lock = threading.Lock()
def create_genesis_block(self):
return Block(0, [], int(time.time()), "0")
def get_latest_block(self):
return self.chain[-1]
def mine_pending_transactions(self, miner_address):
with self.lock:
block = Block(len(self.chain), self.pending_transactions, int(time.time()), self.get_latest_block().hash)
block.mine_block(self.difficulty)
self.chain.append(block)
self.pending_transactions = [
{"from": "network", "to": miner_address, "amount": self.mining_reward}
]
def add_transaction(self, transaction):
if not all(k in transaction for k in ("from", "to", "amount", "signature")):
raise ValueError("Invalid transaction")
public_key = rsa.PublicKey.load_pkcs1(transaction['from'].encode())
message = f"{transaction['from']}{transaction['to']}{transaction['amount']}".encode()
try:
public_key.verify(
transaction['signature'],
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
except:
raise ValueError("Invalid transaction signature")
self.pending_transactions.append(transaction)
def is_chain_valid(self):
for i in range(1, len(self.chain)):
current_block = self.chain[i]
previous_block = self.chain[i-1]
if current_block.hash != current_block.calculate_hash():
return False
if current_block.previous_hash != previous_block.hash:
return False
return True
def add_node(self, address):
parsed_url = urlparse(address)
self.nodes.add(parsed_url.netloc)
def replace_chain(self):
network = self.nodes
longest_chain = None
max_length = len(self.chain)
for node in network:
response = requests.get(f'http://{node}/chain')
if response.status_code == 200:
length = response.json()['length']
chain = response.json()['chain']
if length > max_length and self.is_chain_valid(chain):
max_length = length
longest_chain = chain
if longest_chain:
self.chain = longest_chain
return True
return False
def save_blockchain(blockchain, filename):
with open(filename, 'w') as f:
json.dump([vars(block) for block in blockchain.chain], f)
def load_blockchain(filename):
with open(filename, 'r') as f:
chain_data = json.load(f)
blockchain = Blockchain()
blockchain.chain = [Block(**block_data) for block_data in chain_data]
return blockchain
# Network functionality
def start_node(blockchain, port):
node = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
node.bind(('', port))
node.listen(5)
print(f"Node listening on port {port}")
while True:
client, addr = node.accept()
threading.Thread(target=handle_client, args=(client, blockchain)).start()
def handle_client(client, blockchain):
request = client.recv(1024).decode()
if request == "GET_CHAIN":
client.send(json.dumps([vars(block) for block in blockchain.chain]).encode())
client.close()
# Database functionality
def init_db():
conn = sqlite3.connect('blockchain.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS blocks
(index INTEGER PRIMARY KEY, transactions TEXT, timestamp INTEGER, previous_hash TEXT, nonce INTEGER, hash TEXT)''')
conn.commit()
conn.close()
def save_block_to_db(block):
conn = sqlite3.connect('blockchain.db')
c = conn.cursor()
c.execute("INSERT INTO blocks VALUES (?, ?, ?, ?, ?, ?)",
(block.index, json.dumps(block.transactions), block.timestamp, block.previous_hash, block.nonce, block.hash))
conn.commit()
conn.close()
def load_blockchain_from_db():
conn = sqlite3.connect('blockchain.db')
c = conn.cursor()
c.execute("SELECT * FROM blocks ORDER BY index")
blocks = c.fetchall()
conn.close()
blockchain = Blockchain()
blockchain.chain = [Block(b[0], json.loads(b[1]), b[2], b[3]) for b in blocks]
for block in blockchain.chain:
block.nonce = block.nonce
block.hash = block.hash
return blockchain
# Usage example
blockchain = Blockchain()
init_db()
# Generate RSA key pair for signing transactions
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048
)
public_key = private_key.public_key()
# Example transaction
transaction = {
"from": public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.PKCS1
).decode(),
"to": "recipient_address",
"amount": 5
}
# Sign the transaction
signature = private_key.sign(
f"{transaction['from']}{transaction['to']}{transaction['amount']}".encode(),
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
transaction['signature'] = signature
blockchain.add_transaction(transaction)
blockchain.mine_pending_transactions("miner_address")
# Save the blockchain to file and database
save_blockchain(blockchain, 'blockchain.json')
for block in blockchain.chain:
save_block_to_db(block)
# Start the node
threading.Thread(target=start_node, args=(blockchain, 5000)).start()
# In a real-world scenario, you would implement more comprehensive error handling,
# logging, and security measures. This example provides a basic framework that can
# be extended and improved upon.
```
This implementation includes:
1. A basic blockchain structure with blocks and transactions
2. Proof-of-Work consensus mechanism
3. Transaction signing and verification using RSA
4. Network functionality for distributed nodes
5. Persistent storage using both file-based and SQLite database storage
6. A simple node server to handle basic network requests
To make this production-ready, you would need to add more robust error handling, implement a more advanced consensus mechanism, add more comprehensive testing, and optimize for performance. Additionally, you'd want to implement a proper API, add more security features, and create a user interface for interacting with the blockchain.