Let’s Make the Tiniest Blockchain Bigger

Note: This article assumes you’ve read part one.
The tiniest blockchain was extremely simple, and it was relatively easy to make. But, with its simplicity came a few flaws. First, SnakeCoin only ran on one single machine, so it was far from distributed, let alone decentralized. Second, blocks could be added to the chain as fast as the host computer could create a Python object and add it to a list. In the case of a simple blockchain, that’s not a problem, but we’re now going to let SnakeCoin be an actual cryptocurrency so we’ll need control the amount of blocks (and coins) that can be created at a time.

From now on, SnakeCoin’s data will be transactions, so each block’s data field will be a list of some transactions. We’ll define a transaction as follows. Each transaction will be a JSON object detailing the sender of the coin, the receiver of the coin, and the amount of SnakeCoin that is being transferred. Note: Transactions are in JSON format for a reason I’ll detail shortly.

{
  "from": "71238uqirbfh894-random-public-key-a-alkjdflakjfewn204ij",
  "to": "93j4ivnqiopvh43-random-public-key-b-qjrgvnoeirbnferinfo",
  "amount": 3
}

Enter fullscreen mode Exit fullscreen mode

Now that we know what our transactions will look like, we need a way to add them to one of the computers in our blockchain network, called a node. To do that, we’ll create a simple HTTP server so that any user can let our nodes know that a new transaction has occurred. A node will be able to accept a POST request with a transaction (like above) as the request body. This is why transactions are JSON formatted; we need them to be transmitted to our server in a request body.

pip install flask # Install our web server framework first

Enter fullscreen mode Exit fullscreen mode

from flask import Flask
from flask import request
node = Flask(__name__)

# Store the transactions that # this node has in a list this_nodes_transactions = []

@node.route('/txion', methods=['POST'])
def transaction():
  if request.method == 'POST':
    # 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.run()

Enter fullscreen mode Exit fullscreen mode

Awesome! Now we have a way to keep a record of users when they send SnakeCoins to each other. This is why people refer to blockchains as public, distributed ledgers: all transactions are stored for all to see and are stored on every node in the network.

But, a question arises: where do people get SnakeCoins from? Nowhere, yet. There’s no such thing as a SnakeCoin yet, because not one coin has been created and issued yet. To create new coins, people have to mine new blocks of SnakeCoin. When they successfully mine new blocks, a new SnakeCoin is created and rewarded to the person who mined the block. The coin then gets circulated once the miner sends the SnakeCoin to another person.

We don’t want it to be too easy to mine new SnakeCoin blocks, because that will create too many SnakeCoins and they will have little value. Conversely, we don’t want it to be too hard to mine new blocks, because there wouldn’t be enough coins for everyone to spend, and they would be too expensive for our liking. To control the difficulty of mining new SnakeCoins, we’ll implement a Proof-of-Work (PoW) algorithm. A Proof-of-Work algorithm is essentially an algorithm that generates an item that is difficult to create but easy to verify. The item is called the proof and, as it sounds, it is proof that a computer performed a certain amount of work.

In SnakeCoin, we’ll create a somewhat simple Proof-of-Work algorithm. To create a new block, a miner’s computer will have to increment a number. When that number is divisible by 9 (the number of letters in “SnakeCoin”) and the proof number of the last block, a new SnakeCoin block will be mined and the miner will be given a brand new SnakeCoin.

# ...blockchain # ...Block class definition 
miner_address = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi"

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

Enter fullscreen mode Exit fullscreen mode

Now, we can control the number of blocks mined in a certain time period, and we can issue new coins for people in the network to send to each other. But like we said, we’re only doing this on one computer. If blockchains are decentralized, how do we make sure that the same chain is on every node? To do this, we make each node broadcast its version of the chain to the others and allow them to receive the chains of other nodes. After that, each node has to verify the other nodes’ chains so that the every node in the network can come to a consensus of what the resulting blockchain will look like. This is called a consensus algorithm.

Our consensus algorithm will be rather simple: if a node’s chain is different from another’s (i.e. there is a conflict), then the longest chain in the network stays and all shorter chains will be deleted. If there is no conflict between the chains in our network, then we carry on.

@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 block in chain_to_send:
    block_index = str(block.index)
    block_timestamp = str(block.timestamp)
    block_data = str(block.data)
    block_hash = block.hash
    block = {
      "index": block_index,
      "timestamp": block_timestamp,
      "data": block_data,
      "hash": block_hash
    }
  # Send our chain to whomever requested it   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 wasn't ours,   # then we set our chain to the longest   blockchain = longest_chain

Enter fullscreen mode Exit fullscreen mode

We’re just about done now. After running the full SnakeCoin server code, run the following commands in your terminal. Assuming you have cURL installed.

  1. Create a transaction.
curl "localhost:5000/txion" \
     -H "Content-Type: application/json" \
     -d '{"from": "akjflw", "to":"fjlakdj", "amount": 3}'

Enter fullscreen mode Exit fullscreen mode

  1. Mine a new block.
curl localhost:5000/mine

Enter fullscreen mode Exit fullscreen mode

  1. Check out the results. From the client window, we see this.

With a little bit of pretty printing we see that after mining we get some cool information on our new block.

{
  "index": 2,
  "data": {
    "transactions": [
      {
        "to": "fjlakdj",
        "amount": 3,
        "from": "akjflw"
      },
      {
        "to": "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi",
        "amount": 1,
        "from": "network"
      }
    ],
    "proof-of-work": 36
  },
  "hash": "151edd3ef6af2e7eb8272245cb8ea91b4ecfc3e60af22d8518ef0bba8b4a6b18",
  "timestamp": "2017-07-23 11:23:10.140996"
}

Enter fullscreen mode Exit fullscreen mode

And that’s it! We’ve made a fairly sized blockchain at this point. Now, SnakeCoin can be launched on multiple machines to create a network, and real SnakeCoins can be mined. Please feel free to tinker with the SnakeCoin server code as much as you’d like, and ask as many questions as you need! In the next part, we’ll discuss creating a SnakeCoin wallet, so users can send, receive, and store their SnakeCoins.

Thank you very much for reading!
Twitter, Github, Snapchat, Medium, Instagram

原文链接:Let’s Make the Tiniest Blockchain Bigger

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容