Forked from aunyks/snakecoin-server-full-code.py
Last active
January 4, 2019 03:19
-
-
Save dpino/07a0e90d559a959eb73fecf58a3fea92 to your computer and use it in GitHub Desktop.
Revisions
-
dpino revised this gist
Jan 14, 2018 . 1 changed file with 140 additions and 149 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,171 +1,162 @@ #!/usr/bin/env python # Source https://gist.github.com/aunyks/47d157f8bc7d1829a729c2a6a919c173 # Modifications: # - Can pass port number as command line argument. # - Added GET method /add_peer. # - On retrieving blockchain, call consensus to synchronize with other peers. # - On updating the current blockchain from a peers' blockchain, convert list # of JSON blocks to native Block objects. import datetime as date import hashlib as hasher import json import requests import sys from flask import Flask from flask import request node = Flask(__name__) # Define what a Snakecoin block is. class Block: def __init__(self, index, timestamp, data, previous_hash): self.index = index self.timestamp = timestamp self.data = data self.previous_hash = previous_hash self.hash = self.hash_block() def hash_block(self): sha = hasher.sha256() sha.update(self.attributes()) return sha.hexdigest() def attributes(self): return str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash) def create_genesis_block(): return Block(0, date.datetime.now(), { "proof-of-work": 9, "transactions": None, }, "0") miner_address = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi" blockchain = [] peer_nodes = [] mining = True # Transaction submit. transactions = [] @node.route('/transaction', methods=['POST']) def transaction(): if request.method == 'POST': transaction = request.get_json() transactions.append(transaction) print "New transaction" print "FROM: {}".format(transaction['from']) print "TO: {}".format(transaction['to']) print "AMOUNT: {}\n".format(transaction['amount']) return "Transaction submission successful\n" @node.route('/blocks', methods=['GET']) def get_blocks(): ret = [] for block in consensus(): ret.append({ "index": str(block.index), "timestamp": str(block.timestamp), "data": str(block.data), "hash": block.hash, }) return json.dumps(ret) # Update the current blockchain to the longest blockchain across all other # peer nodes. def consensus(): global blockchain longest_chain = blockchain for chain in find_other_chains(): if len(longest_chain) < len(chain): longest_chain = chain return update_blockchain(longest_chain) # Updates current blockchain. If updated is needed, converts JSON blockchain to # list of blocks. def update_blockchain(src): if len(src) <= len(blockchain): return blockchain ret = [] for b in src: ret.append(Block(b['index'], b['timestamp'], b['data'], b['hash'])) return ret def find_other_chains(): ret = [] for peer in peer_nodes: response = requests.get('http://%s/blocks' % peer) if response.status_code == 200: print("blocks from peer: " + response.content) ret.append(json.loads(response.content)) return ret @node.route('/add_peer', methods=['GET']) def add_peer(): host = request.args['host'] if 'host' in request.args else 'localhost' port = request.args['port'] peer = host + ':' + port peer_nodes.append(peer) print("Peer added: %s" % peer) return "" @node.route('/mine', methods = ['GET']) def mine(): last_block = blockchain[len(blockchain) - 1] last_proof = last_block.data['proof-of-work'] proof = proof_of_work(last_proof) transactions.append( {"from": "network", "to": miner_address, "amount": 1} ) data = { "proof-of-work": proof, "transactions": list(transactions) } index = last_block.index + 1 timestamp = date.datetime.now() # Empty transactions list. transactions[:] = [] # Create a mined block. block = Block(index, timestamp, data, last_block.hash) blockchain.append(block) return json.dumps({ "index": index, "timestamp": str(timestamp), "data": data, "hash": last_block.hash }) + "\n" def proof_of_work(last_proof): incrementor = last_proof + 1 while not (incrementor % 9 == 0 and incrementor % last_proof == 0): incrementor += 1 return incrementor def main(): port = 5000 if len(sys.argv) > 1: port = sys.argv[1] blockchain.append(create_genesis_block()) node.run(port=port) if __name__ == '__main__': main() -
aunyks revised this gist
Jul 23, 2017 . 1 changed file with 7 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -55,8 +55,8 @@ def transaction(): # Because the transaction was successfully # submitted, we log it to our console print "New transaction" print "FROM: {}".format(new_txion['from'].encode('ascii','replace')) print "TO: {}".format(new_txion['to'].encode('ascii','replace')) print "AMOUNT: {}\n".format(new_txion['amount']) # Then we let the client know it worked out return "Transaction submission successful\n" @@ -161,10 +161,11 @@ def mine(): blockchain.append(mined_block) # Let the client know we mined a block return json.dumps({ "index": new_block_index, "timestamp": str(new_block_timestamp), "data": new_block_data, "hash": last_block_hash }) + "\n" node.run() -
aunyks created this gist
Jul 23, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,170 @@ from flask import Flask from flask import request import json import requests import hashlib as hasher import datetime as date node = Flask(__name__) # Define what a Snakecoin block is class Block: def __init__(self, index, timestamp, data, previous_hash): self.index = index self.timestamp = timestamp self.data = data self.previous_hash = previous_hash self.hash = self.hash_block() def hash_block(self): sha = hasher.sha256() sha.update(str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash)) return sha.hexdigest() # Generate genesis block def create_genesis_block(): # Manually construct a block with # index zero and arbitrary previous hash return Block(0, date.datetime.now(), { "proof-of-work": 9, "transactions": None }, "0") # A completely random address of the owner of this node miner_address = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi" # This node's blockchain copy blockchain = [] blockchain.append(create_genesis_block()) # Store the transactions that # this node has in a list this_nodes_transactions = [] # Store the url data of every # other node in the network # so that we can communicate # with them peer_nodes = [] # A variable to deciding if we're mining or not mining = True @node.route('/txion', methods=['POST']) def transaction(): # On each new POST request, # we extract the transaction data new_txion = request.get_json() # Then we add the transaction to our list this_nodes_transactions.append(new_txion) # Because the transaction was successfully # submitted, we log it to our console print "New transaction" print "FROM: {}".format(new_txion['from']) print "TO: {}".format(new_txion['to']) print "AMOUNT: {}\n".format(new_txion['amount']) # Then we let the client know it worked out return "Transaction submission successful\n" @node.route('/blocks', methods=['GET']) def get_blocks(): chain_to_send = blockchain # Convert our blocks into dictionaries # so we can send them as json objects later for i in range(len(chain_to_send)): block = chain_to_send[i] block_index = str(block.index) block_timestamp = str(block.timestamp) block_data = str(block.data) block_hash = block.hash chain_to_send[i] = { "index": block_index, "timestamp": block_timestamp, "data": block_data, "hash": block_hash } chain_to_send = json.dumps(chain_to_send) return chain_to_send def find_new_chains(): # Get the blockchains of every # other node other_chains = [] for node_url in peer_nodes: # Get their chains using a GET request block = requests.get(node_url + "/blocks").content # Convert the JSON object to a Python dictionary block = json.loads(block) # Add it to our list other_chains.append(block) return other_chains def consensus(): # Get the blocks from other nodes other_chains = find_new_chains() # If our chain isn't longest, # then we store the longest chain longest_chain = blockchain for chain in other_chains: if len(longest_chain) < len(chain): longest_chain = chain # If the longest chain isn't ours, # then we stop mining and set # our chain to the longest one blockchain = longest_chain def proof_of_work(last_proof): # Create a variable that we will use to find # our next proof of work incrementor = last_proof + 1 # Keep incrementing the incrementor until # it's equal to a number divisible by 9 # and the proof of work of the previous # block in the chain while not (incrementor % 9 == 0 and incrementor % last_proof == 0): incrementor += 1 # Once that number is found, # we can return it as a proof # of our work return incrementor @node.route('/mine', methods = ['GET']) def mine(): # Get the last proof of work last_block = blockchain[len(blockchain) - 1] last_proof = last_block.data['proof-of-work'] # Find the proof of work for # the current block being mined # Note: The program will hang here until a new # proof of work is found proof = proof_of_work(last_proof) # Once we find a valid proof of work, # we know we can mine a block so # we reward the miner by adding a transaction this_nodes_transactions.append( { "from": "network", "to": miner_address, "amount": 1 } ) # Now we can gather the data needed # to create the new block new_block_data = { "proof-of-work": proof, "transactions": list(this_nodes_transactions) } new_block_index = last_block.index + 1 new_block_timestamp = this_timestamp = date.datetime.now() last_block_hash = last_block.hash # Empty transaction list this_nodes_transactions[:] = [] # Now create the # new block! mined_block = Block( new_block_index, new_block_timestamp, new_block_data, last_block_hash ) blockchain.append(mined_block) # Let the client know we mined a block return json.dumps({ "index": str(new_block_index), "timestamp": str(new_block_timestamp), "data": str(new_block_data), "hash": str(last_block_hash) }) node.run()