defnew_transaction(self, sender, recipient, amount): """ Creates a new transaction to go into the next mined Block :param sender: <str> Address of the Sender :param recipient: <str> Address of the Recipient :param amount: <int> Amount :return: <int> The index of the Block that will hold this transaction """
# Create the genesis block self.new_block(previous_hash=1, proof=100)
defnew_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 """
# Reset the current list of transactions self.current_transactions = []
self.chain.append(block) return block
defnew_transaction(self, sender, recipient, amount): """ Creates a new transaction to go into the next mined Block :param sender: <str> Address of the Sender :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, })
@staticmethod defhash(block): """ Creates a SHA-256 hash of a Block :param block: <dict> Block :return: <str> """
# 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()
defproof_of_work(self, last_proof): """ Simple Proof of Work Algorithm: - Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p' - p is the previous proof, and p' is the new proof :param last_proof: <int> :return: <int> """
# Check that the required fields are in the POST'ed data required = ['sender', 'recipient', 'amount'] ifnotall(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('/mine', methods=['GET']) defmine(): # 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. # 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)
defregister_node(self, address): """ Add a new node to the list of nodes :param address: <str> Address of node. Eg. 'http://192.168.0.5:5000' :return: None """
defvalid_chain(self, chain): """ Determine if a given blockchain is valid :param chain: <list> A blockchain :return: <bool> 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 if block['previous_hash'] != self.hash(last_block): returnFalse
# Check that the Proof of Work is correct ifnotself.valid_proof(last_block['proof'], block['proof']): returnFalse
last_block = block current_index += 1
returnTrue
defresolve_conflicts(self): """ This is our Consensus Algorithm, it resolves conflicts by replacing our chain with the longest one in the network. :return: <bool> 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 andself.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 returnTrue