Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions basic_block_gp/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ def proof_of_work(self, block):
:return: A valid proof for the provided block
"""
# TODO
pass
# return proof
proof = 0

while self.valid_proof(block, proof) is False:
proof += 1

return proof

@staticmethod
def valid_proof(block_string, proof):
Expand All @@ -109,8 +113,13 @@ def valid_proof(block_string, proof):
:return: True if the resulting hash is a valid proof, False otherwise
"""
# TODO
pass
guess = f'{block_string}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()

# return guess_hash[:6] == "000000"
# return True or False
result = True if guess_hash[:6] == "000000" else False
return result

def valid_chain(self, chain):
"""
Expand All @@ -131,9 +140,13 @@ def valid_chain(self, chain):
print("\n-------------------\n")
# Check that the hash of the block is correct
# TODO: Return false if hash isn't correct
if block['previous_hash'] != self.hash(prev_block):
return False

# Check that the Proof of Work is correct
# TODO: Return false if proof isn't correct
if not self.valid_proof(prev_block['proof'], block['proof']):
return False

prev_block = block
current_index += 1
Expand All @@ -154,16 +167,23 @@ def valid_chain(self, chain):
@app.route('/mine', methods=['GET'])
def mine():
# We run the proof of work algorithm to get the next proof...
proof = blockchain.proof_of_work()
last_block = blockchain.last_block
last_proof = last_block['proof']
proof = blockchain.proof_of_work(last_proof)

# We must receive a reward for finding the proof.
# TODO:
# The sender is "0" to signify that this node has mine a new coin
# The recipient is the current node, it did the mining!
# The amount is 1 coin as a reward for mining the next block
blockchain.new_transaction(
sender='0',
recipient=node_identifier,
amount =1)

# Forge the new Block by adding it to the chain
# TODO
block = blockchain.new_block(proof, blockchain.hash(blockchain.last_block))

# Send a response with the new block
response = {
Expand Down Expand Up @@ -198,6 +218,8 @@ def new_transaction():
def full_chain():
response = {
# TODO: Return the chain and its current length
'currentChain': blockchain.chain,
'length': len(blockchain.chain)
}
return jsonify(response), 200

Expand Down
232 changes: 230 additions & 2 deletions client_mining_p/blockchain.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,230 @@
# Paste your version of blockchain.py from the basic_block_gp
# folder here
import hashlib
import json
from time import time
from uuid import uuid4

from flask import Flask, jsonify, request


class Blockchain(object):
def __init__(self):
self.chain = []
self.current_transactions = []
self.nodes = set()

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

def new_block(self, proof, previous_hash=None):
"""
Create a new Block in the Blockchain

:param proof: <int> The proof given by the Proof of Work algorithm
:param previous_hash: (Optional) <str> Hash of previous Block
:return: <dict> 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: <str> Address of the Recipient
:param recipient: <str> Address of the Recipient
:param amount: <int> Amount
:return: <int> 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

@staticmethod
def hash(block):
"""
Creates a SHA-256 hash of a Block

:param block": <dict> Block
"return": <str>
"""


# json.dumps converts json into a string
# hashlib.sha246 is used to createa hash
# It requires a `bytes-like` object, which is what
# .encode() does. It convertes the string to bytes.
# We must make sure that the Dictionary is Ordered,
# or we'll have inconsistent hashes

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

# By itself, this function returns the hash in a raw string
# that will likely include escaped characters.
# This can be hard to read, but .hexdigest() converts the
# hash to a string using hexadecimal characters, which is
# easer to work with and understand.
return hashlib.sha256(block_string).hexdigest()

@property
def last_block(self):
return self.chain[-1]

def proof_of_work(self, block):
"""
Simple Proof of Work Algorithm
Find a number p such that hash(last_block_string, p) contains 6 leading
zeroes
:return: A valid proof for the provided block
"""
# TODO
proof = 0

while self.valid_proof(block, proof) is False:
proof += 1

return proof

@staticmethod
def valid_proof(block_string, proof):
"""
Validates the Proof: Does hash(block_string, proof) contain 6
leading zeroes? Return true if the proof is valid
:param block_string: <string> The stringified block to use to
check in combination with `proof`
:param proof: <int?> The value that when combined with the
stringified previous block results in a hash that has the
correct number of leading zeroes.
:return: True if the resulting hash is a valid proof, False otherwise
"""
# TODO
guess = f'{block_string}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()

# return guess_hash[:6] == "000000"
# return True or False
result = True if guess_hash[:6] == "000000" else False
return result

def valid_chain(self, chain):
"""
Determine if a given blockchain is valid. We'll need this
later when we are a part of a network.

:param chain: <list> A blockchain
:return: <bool> True if valid, False if not
"""

prev_block = chain[0]
current_index = 1

while current_index < len(chain):
block = chain[current_index]
print(f'{prev_block}')
print(f'{block}')
print("\n-------------------\n")
# Check that the hash of the block is correct
# TODO: Return false if hash isn't correct
if block['previous_hash'] != self.hash(prev_block):
return False

# Check that the Proof of Work is correct
# TODO: Return false if proof isn't correct
if not self.valid_proof(prev_block['proof'], block['proof']):
return False

prev_block = block
current_index += 1

return True


# Instantiate our 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
last_proof = last_block['proof']
proof = blockchain.proof_of_work(last_proof)

# We must receive a reward for finding the proof.
# TODO:
# The sender is "0" to signify that this node has mine a new coin
# The recipient is the current node, it did the mining!
# The amount is 1 coin as a reward for mining the next block
blockchain.new_transaction(
sender='0',
recipient=node_identifier,
amount =1)

# Forge the new Block by adding it to the chain
# TODO
block = blockchain.new_block(proof, blockchain.hash(blockchain.last_block))

# Send a response with the new block
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 = {
# TODO: Return the chain and its current length
'currentChain': blockchain.chain,
'length': len(blockchain.chain)
}
return jsonify(response), 200


# Run the program on port 5000
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

23 changes: 22 additions & 1 deletion client_mining_p/miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@


# TODO: Implement functionality to search for a proof
def valid_proof(last_proof, proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:6] == "000000"

def proof_of_work(last_proof):
proof = 0
while valid_proof(last_proof, proof) is False:
proof +=1
return proof

if __name__ == '__main__':
# What node are we interacting with?
Expand All @@ -24,4 +33,16 @@
# TODO: If the server responds with 'New Block Forged'
# add 1 to the number of coins mined and print it. Otherwise,
# print the message from the server.
pass
last = requests.get(url=node + "/last_proof")
last_proof = last.json()['proof']
print('last proof', last_proof)
data = {
'proof': proof_of_work(last_proof)
}
print('next proof', data['proof'])
res = requests.post(url = f'{node}/mine', json = data)

if (res.json()['index']):
coins_mined+=1
print(f'Total Coins Mined: {coins_mined}')
print(res.json()['message'])