Files
Blockchain/blockchain.py

138 lines
3.6 KiB
Python

#!/usr/bin/env python
import hashlib
from time import time
import json
import requests
from urllib.parse import urlparse
DIFFICULTY = 4
class Block:
def __init__(self, index, timestamp, transactions, previous_hash, proof):
self.index = index
self.timestamp = timestamp
self.transactions = transactions
self.previous_hash = previous_hash
self.proof = proof
self.hash = self.hash()
def hash(self):
data = self.__dict__
data["transactions"] = [t.__dict__ for t in self.transactions]
block_string = json.dumps(data, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
# def toJSON(self):
# return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
class Transaction:
def __init__(self, sender, recipient, amount):
self.sender = sender
self.recipient = recipient
self.amount = amount
def __str__(self):
return f"FROM: {self.sender} TO: {self.recipient} AMOUNT: {self.amount}"
class Blockchain:
def __init__(self):
self.blocks = []
self.blocks.append(self.create_first_block())
self.transactions = []
self.nodes = set()
def register_node(self, address):
parsed_url = urlparse(address).netloc
self.nodes.add(parsed_url)
def create_first_block(self):
return Block(1, time(), [], 1, 100)
def new_transaction(self, transaction):
self.transactions.append(transaction)
def new_block(self, block):
self.transactions = []
self.blocks.append(block)
def proof_of_work(self, last_proof):
proof = 0
while not self.valid_proof(proof, last_proof):
proof += 1
return proof
@staticmethod
def valid_proof(proof, last_proof):
guess = f"{last_proof}{proof}".encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:DIFFICULTY] == "0" * DIFFICULTY
def valid_chain(self, chain):
last_block = chain[0]
current_index = 1
while current_index < len(chain):
block = chain[current_index]
if block["previous_hash"] != last_block["hash"]:
return False
if not self.valid_proof(block["proof"], last_block["proof"]):
return False
last_block = block
current_index += 1
return True
def json_to_transactions(self, transactions_json):
transactions = [
Transaction(
transaction["sender"],
transaction["recipient"],
transaction["amount"],
)
for transaction in transactions_json
]
return transactions
def json_to_chain(self, chain_json):
chain = [
Block(
block["index"],
block["timestamp"],
self.json_to_transactions(block["transactions"]),
block["previous_hash"],
block["proof"],
)
for block in chain_json
]
return chain
def resolve_conflicts(self):
neighbours = self.nodes
new_chain = None
max_lengh = len(self.blocks)
for node in neighbours:
response = requests.get(f"http://{node}/chain")
chain = response.json()
length = len(chain)
if length > max_lengh and self.valid_chain(chain):
max_lengh = length
new_chain = self.json_to_chain(chain)
if new_chain:
self.blocks = new_chain
return True
return False