🎓Build a blockchain prototype using Python

I’ve completed the first course of my DIY-MBA! 💥

This was a nice, pretty short Udemy course in which an instructor takes you through:

  • A few blockchain fundamentals (which I mostly knew already so went over quickly)
  • Building a mini prototype of a blockchain using Python, with a client and nodes (“miners”) implementing
    • For the clients
      • Issuing new public/private key pairs (effectively a new wallet)
      • Generating and signing transactions with the private key
      • Sending transactions to one of the miners
    • For the miners
      • Receiving & validating transactions (ensuring the signed transaction must have come from someone with the private key)
      • Mining a new block: taking transactions that aren’t yet on the chain, bundling them, and trying to find the nonce value (a number) which makes the new block pass the hashing difficulty challenge of the network (in this case the hash had to start with 2 0s). This is the idea of the proof of work algorithm
      • The miner issuing itself a block reward as part of this newly mined block
      • Miners being aware of other miners’ chains (polling for them) and updating their blockchain version if there is a longer valid chain out there (checking that all previous_hash values are actually equal to the hash of the previous block), and mining on top of that one (this is the idea of the consensus algorithm)

It was nice to get a bit of a hands-on view of some of these key techniques after reading about them for a while. They’re really not that complicated and pretty brilliant.

Here’s a quick demo of the final prototype:

In terms of “scaffolding” this was also a good opportunity to learn more about:

  • Python’s Flask framework for web services
  • Bootstrap & Font Awesome
  • Do some more JQuery and AJAX request (although I think these are both pretty out of fashion)
  • Play more with Repl.it which I love (an in-browser IDE and hosting service)
Repl.it

For non-blockchain things e.g the UIs I often just copied what the instructor had done but for the blockchain bits would try to do it myself first. Took about a dozen hours in total.

Cool code snippets

Verifying transaction signatures to respond to the client’s request for a new transaction (and as a gate for starting to mine it)

  def verify_transaction_signature(self, sender_public_key, signature, transaction):
    public_key = RSA.importKey(binascii.unhexlify(sender_public_key))
    verifier = PKCS1_v1_5.new(public_key)
    h = SHA.new(str(transaction).encode('utf8'))
    return verifier.verify(h, binascii.unhexlify(signature))

(Note: think instructor has a mistake in his implementation)

Proof of work algorithm:

  @staticmethod 
  def valid_proof(transactions, last_hash, nonce, difficulty=MINING_DIFFICULTY):
    guess = (str(transactions) + str(last_hash) + str(nonce)).encode('utf-8')
    h = SHA256.new()
    h.update(guess)
    guess_hash = h.hexdigest()
    # Return true if first N digits of the hash are same number of 0s as the difficulty 
    return guess_hash[:difficulty] == '0' * difficulty

  # Find the nonce which creates a hash which has a minimum number of 0s at the start
  def proof_of_work(self):
      last_block = self.chain[-1]
      last_hash = self.hash(last_block)
      nonce = 0 
      while(self.valid_proof(self.transactions, last_hash, nonce)) is False:
        nonce+=1
      return nonce

Validate a chain. Are all the hashes what they say they are 🙂

  def valid_chain(self, chain):
      last_block = chain[0]
      current_index = 1

      while current_index < len(chain):
          block = chain[current_index]
          if block['previous_hash'] != Blockchain.hash(last_block):
              return False

          transactions = block['transactions'][:-1]
          transaction_elements = ['sender_public_key', 'recipient_public_key', 'amount']
          transactions = [OrderedDict((k, transaction[k]) for k in transaction_elements) for transaction in transactions]

          if not self.valid_proof(transactions, block['previous_hash'], block['nonce'], MINING_DIFFICULTY):
              return False

          last_block = block
          current_index += 1

      return True

Fork it

Both the client and node implementations are on repl.it meaning they’re (1) public and (2) extremely easy to run, just fork and hit Play.

https://repl.it/@ernopp/bloknode1

https://repl.it/@ernopp/blokclient

3 comments

  1. This looks great! One thing I never understood about the real blockchain though: are transactions hashed as part of the mining process or just included as some kind of metadata once a block has been found?

    If there’s a lot of transactions, what’s the incentive for a miner to include them when hashing? They get paid for the block either way. Is that where transaction fees come in?

    Anyway, I’m enjoying the blog so far. Keep it up!

    Like

    • Thanks man! Good Qs…

      As far as I understand, and from what we implemented in the course, the list of transactions along with a nonce value is all bundled together and hashed. The nonce value is figured out by the miner so that the resulting hash has certain property (this is the proof of work).

      Yeah in the real Bitcoin the incentive for miners to include transactions is that they contain fees (and as a miner when you create the block you can direct these fees towards yourself). Miners will favour transactions with higher fees first which is why the higher the fee you add the faster your transaction gets validated by the network.

      I think another incentive for taking transactions in general (even if fees weren’t a thing like in the prototype) is that they help you having the longest chain, and you want to always stay as close as possible to longest chain otherwise you run the risk of mining a block which doesn’t get accepted by the network (because there’s another longer chain somewhere else) which was lost work.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s