0% found this document useful (0 votes)
51 views

Block Chain Python Code

This document defines a Blockchain class that implements a basic blockchain with proof-of-work consensus. The class includes methods for adding transactions, mining new blocks, registering nodes, and resolving conflicts to maintain consensus across the decentralized network. A Flask API is also defined to allow interaction with the blockchain.

Uploaded by

Mido Abdullah
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
51 views

Block Chain Python Code

This document defines a Blockchain class that implements a basic blockchain with proof-of-work consensus. The class includes methods for adding transactions, mining new blocks, registering nodes, and resolving conflicts to maintain consensus across the decentralized network. A Flask API is also defined to allow interaction with the blockchain.

Uploaded by

Mido Abdullah
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 12

import hashlib

import json

from time import time

from urllib.parse import urlparse

from uuid import uuid4

import requests

from flask import Flask, jsonify, request

class Blockchain:

def __init__(self):

self.current_transactions = []

self.chain = []

self.nodes = set()

# Create the genesis block

self.new_block(previous_hash='1', proof=100)

def register_node(self, address):

"""

Add a new node to the list of nodes

:param address: Address of node. Eg. 'http://192.168.0.5:5000'

"""
parsed_url = urlparse(address)

if parsed_url.netloc:

self.nodes.add(parsed_url.netloc)

elif parsed_url.path:

# Accepts an URL without scheme like '192.168.0.5:5000'.

self.nodes.add(parsed_url.path)

else:

raise ValueError('Invalid URL')

def valid_chain(self, chain):

"""

Determine if a given blockchain is valid

:param chain: A blockchain

:return: True if valid, False if not

"""

last_block = chain[0]

current_index = 1

while current_index < len(chain):

block = chain[current_index]

print(f'{last_block}')

print(f'{block}')
print("\n-----------\n")

# Check that the hash of the block is correct

last_block_hash = self.hash(last_block)

if block['previous_hash'] != last_block_hash:

return False

# Check that the Proof of Work is correct

if not self.valid_proof(last_block['proof'], block['proof'], last_block_hash):

return False

last_block = block

current_index += 1

return True

def resolve_conflicts(self):

"""

This is our consensus algorithm, it resolves conflicts

by replacing our chain with the longest one in the network.

:return: True if our chain was replaced, False if not

"""

neighbours = self.nodes

new_chain = None
# We're only looking for chains longer than ours

max_length = len(self.chain)

# Grab and verify the chains from all the nodes in our network

for node in neighbours:

response = requests.get(f'http://{node}/chain')

if response.status_code == 200:

length = response.json()['length']

chain = response.json()['chain']

# Check if the length is longer and the chain is valid

if length > max_length and self.valid_chain(chain):

max_length = length

new_chain = chain

# Replace our chain if we discovered a new, valid chain longer than ours

if new_chain:

self.chain = new_chain

return True

return False

def new_block(self, proof, previous_hash):

"""
Create a new Block in the Blockchain

:param proof: The proof given by the Proof of Work algorithm

:param previous_hash: Hash of previous Block

:return: New Block

"""

block = {

'index': len(self.chain) + 1,

'timestamp': time(),

'transactions': self.current_transactions,

'proof': proof,

'previous_hash': previous_hash or self.hash(self.chain[-1]),

# Reset the current list of transactions

self.current_transactions = []

self.chain.append(block)

return block

def new_transaction(self, sender, recipient, amount):

"""

Creates a new transaction to go into the next mined Block

:param sender: Address of the Sender

:param recipient: Address of the Recipient


:param amount: Amount

:return: The index of the Block that will hold this transaction

"""

self.current_transactions.append({

'sender': sender,

'recipient': recipient,

'amount': amount,

})

return self.last_block['index'] + 1

@property

def last_block(self):

return self.chain[-1]

@staticmethod

def hash(block):

"""

Creates a SHA-256 hash of a Block

:param block: Block

"""

# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes

block_string = json.dumps(block, sort_keys=True).encode()

return hashlib.sha256(block_string).hexdigest()
def proof_of_work(self, last_block):

"""

Simple Proof of Work Algorithm:

- Find a number p' such that hash(pp') contains leading 4 zeroes

- Where p is the previous proof, and p' is the new proof

:param last_block: <dict> last Block

:return: <int>

"""

last_proof = last_block['proof']

last_hash = self.hash(last_block)

proof = 0

while self.valid_proof(last_proof, proof, last_hash) is False:

proof += 1

return proof

@staticmethod

def valid_proof(last_proof, proof, last_hash):

"""

Validates the Proof

:param last_proof: <int> Previous Proof


:param proof: <int> Current Proof

:param last_hash: <str> The hash of the Previous Block

:return: <bool> True if correct, False if not.

"""

guess = f'{last_proof}{proof}{last_hash}'.encode()

guess_hash = hashlib.sha256(guess).hexdigest()

return guess_hash[:4] == "0000"

# Instantiate the Node

app = Flask(__name__)

# Generate a globally unique address for this node

node_identifier = str(uuid4()).replace('-', '')

# Instantiate the Blockchain

blockchain = Blockchain()

@app.route('/mine', methods=['GET'])

def mine():

# We run the proof of work algorithm to get the next proof...

last_block = blockchain.last_block

proof = blockchain.proof_of_work(last_block)
# We must receive a reward for finding the proof.

# The sender is "0" to signify that this node has mined a new coin.

blockchain.new_transaction(

sender="0",

recipient=node_identifier,

amount=1,

# Forge the new Block by adding it to the chain

previous_hash = blockchain.hash(last_block)

block = blockchain.new_block(proof, previous_hash)

response = {

'message': "New Block Forged",

'index': block['index'],

'transactions': block['transactions'],

'proof': block['proof'],

'previous_hash': block['previous_hash'],

return jsonify(response), 200

@app.route('/transactions/new', methods=['POST'])

def new_transaction():
values = request.get_json()

# Check that the required fields are in the POST'ed data

required = ['sender', 'recipient', 'amount']

if not all(k in values for k in required):

return 'Missing values', 400

# Create a new Transaction

index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])

response = {'message': f'Transaction will be added to Block {index}'}

return jsonify(response), 201

@app.route('/chain', methods=['GET'])

def full_chain():

response = {

'chain': blockchain.chain,

'length': len(blockchain.chain),

return jsonify(response), 200

@app.route('/nodes/register', methods=['POST'])

def register_nodes():
values = request.get_json()

nodes = values.get('nodes')

if nodes is None:

return "Error: Please supply a valid list of nodes", 400

for node in nodes:

blockchain.register_node(node)

response = {

'message': 'New nodes have been added',

'total_nodes': list(blockchain.nodes),

return jsonify(response), 201

@app.route('/nodes/resolve', methods=['GET'])

def consensus():

replaced = blockchain.resolve_conflicts()

if replaced:

response = {

'message': 'Our chain was replaced',

'new_chain': blockchain.chain

}
else:

response = {

'message': 'Our chain is authoritative',

'chain': blockchain.chain

return jsonify(response), 200

if __name__ == '__main__':

from argparse import ArgumentParser

parser = ArgumentParser()

parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')

args = parser.parse_args()

port = args.port

app.run(host='0.0.0.0', port

You might also like