Skip to content

Instantly share code, notes, and snippets.

@dpino
Forked from aunyks/snakecoin-server-full-code.py
Last active January 4, 2019 03:19
Show Gist options
  • Save dpino/07a0e90d559a959eb73fecf58a3fea92 to your computer and use it in GitHub Desktop.
Save dpino/07a0e90d559a959eb73fecf58a3fea92 to your computer and use it in GitHub Desktop.

Revisions

  1. dpino revised this gist Jan 14, 2018. 1 changed file with 140 additions and 149 deletions.
    289 changes: 140 additions & 149 deletions snakecoin-server-full-code.py
    Original file line number Diff line number Diff line change
    @@ -1,171 +1,162 @@
    from flask import Flask
    from flask import request
    #!/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 hashlib as hasher
    import datetime as date
    import sys

    from flask import Flask
    from flask import request

    node = Flask(__name__)

    # Define what a Snakecoin block is
    # 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 __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():
    # 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
    return Block(0, date.datetime.now(), {
    "proof-of-work": 9,
    "transactions": None,
    }, "0")


    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'])
    # Transaction submit.

    transactions = []

    @node.route('/transaction', 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'].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"
    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():
    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
    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():
    # 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
    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)

    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
    # 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():
    # 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": new_block_index,
    "timestamp": str(new_block_timestamp),
    "data": new_block_data,
    "hash": last_block_hash
    }) + "\n"

    node.run()
    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()
  2. @aunyks aunyks revised this gist Jul 23, 2017. 1 changed file with 7 additions and 6 deletions.
    13 changes: 7 additions & 6 deletions snakecoin-server-full-code.py
    Original 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'])
    print "TO: {}".format(new_txion['to'])
    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": str(new_block_index),
    "index": new_block_index,
    "timestamp": str(new_block_timestamp),
    "data": str(new_block_data),
    "hash": str(last_block_hash)
    })
    "data": new_block_data,
    "hash": last_block_hash
    }) + "\n"

    node.run()

  3. @aunyks aunyks created this gist Jul 23, 2017.
    170 changes: 170 additions & 0 deletions snakecoin-server-full-code.py
    Original 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()