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
63 changes: 34 additions & 29 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ https://imgur.com/xSlgvtl

### Part 1 in Class Project
* Basic Setup and Proof of Work (basic_block_gp)
```
pipenv shell
pipenv install
python basic_block_gp/blockchain.py

```
### Part 1 Take Home Project
* Client Miners (client_mining_p)

Expand Down
100 changes: 66 additions & 34 deletions basic_block_gp/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from flask import Flask, jsonify, request


class Blockchain(object):
def __init__(self):
self.chain = []
Expand All @@ -17,32 +16,35 @@ def __init__(self):
def new_block(self, proof, previous_hash=None):
"""
Create a new Block in the Blockchain

A block should have:
* Index
* Timestamp
* List of current transactions
* The proof used to mine this block
* The hash of the previous block

: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 = {
# TODO
'index': len(self.chain) + 1,
'proof': proof,
'timestamp': time(),
'transactions': self.current_transactions,
'previous_hash': previous_hash,
}

# Reset the current list of transactions
self.current_transactions = []
# Append the chain to the block
self.chain.append(block)
# Return the new block
pass
return block

def hash(self, block):
"""
Creates a SHA-256 hash of a Block

:param block": <dict> Block
"return": <str>
"""
Expand All @@ -55,35 +57,26 @@ def hash(self, block):
# We must make sure that the Dictionary is Ordered,
# or we'll have inconsistent hashes

# TODO: Create the block_string

# TODO: Hash this string using sha256
# Create the block_string
block_str = json.dumps(block, sort_keys=True)
str_bytes = block_str.encode()

# Hash this string using sha256
hash_obj = hashlib.sha256(str_bytes)
hash_str = hash_obj.hexdigest()
# By itself, the sha256 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 of hexadecimal characters, which is
# easier to work with and understand

# TODO: Return the hashed block string in hexadecimal format
pass
# Return the hashed block string in hexadecimal format
return hash_str

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

def proof_of_work(self, block):
"""
Simple Proof of Work Algorithm
Stringify the block and look for a proof.
Loop through possibilities, checking each one against `valid_proof`
in an effort to find a number that is a valid proof
:return: A valid proof for the provided block
"""
# TODO
pass
# return proof

@staticmethod
def valid_proof(block_string, proof):
"""
Expand All @@ -96,10 +89,16 @@ def valid_proof(block_string, proof):
correct number of leading zeroes.
:return: True if the resulting hash is a valid proof, False otherwise
"""
# TODO
pass
guess = f'{block_string}{proof}'.encode()

# return True or False
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:6] == '000000'

def new_transaction(self, sender, recipient, amount):
transaction = {"sender": sender, "recipient": recipient, "amount": amount}
self.current_transactions.append(transaction)
return self.last_block["index"] + 1

# Instantiate our Node
app = Flask(__name__)
Expand All @@ -111,27 +110,60 @@ def valid_proof(block_string, proof):
blockchain = Blockchain()


@app.route('/mine', methods=['GET'])
@app.route('/mine', methods=['POST'])
def mine():
# Run the proof of work algorithm to get the next proof
data = request.get_json()

# Forge the new Block by adding it to the chain with the proof
req_params = ['proof', 'id']
if not all(k in data for k in req_params):
response = {
'message': 'Missing required fields.'
}
return jsonify(response), 400

proof_sent = data['proof']

blk_str = json.dumps(blockchain.last_block, sort_keys=True)

is_proof_valid = blockchain.valid_proof(blk_str, proof_sent)
recipient_id = data["id"]

if is_proof_valid:
previous_hash = blockchain.hash(blockchain.last_block)
new_blk = blockchain.new_block(proof_sent, previous_hash)
blockchain.new_transaction(sender="0", recipient=recipient_id, amount=1)

response = {
"message": "Congratulation! New block is found",
"index": new_blk["index"],
"transactions": new_blk["transactions"],
"proof": new_blk["proof"],
"previous_hash": new_blk["previous_hash"]
}
return jsonify(response), 200
else:
return jsonify({'message': 'Invalid Proof. Unsuccessful Try again.'}), 200

@app.route('/chain', methods=['GET'])
def full_chain():
response = {
# TODO: Send a JSON response with the new block
# Return the chain and its current length
'chain': blockchain.chain,
'chain_length': len(blockchain.chain)
}

return jsonify(response), 200


@app.route('/chain', methods=['GET'])
def full_chain():
@app.route('/last_block', methods=['GET'])
def last_block_in_chain():
# last block in chain
last_block = blockchain.chain[-1]
response = {
# TODO: Return the chain and its current length
'last_block': last_block
}
return jsonify(response), 200


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