Blockchain Proof of Concept

in #blockchain6 years ago (edited)

If you are a programmer and have been hearing all of the fuss about THE BLOCKCHAIN but haven't yet looked into it, and were looking for a starting point, this is the post for you! Feel free to skip the buzzword section and get right to the code if you already understand what a blockchain data structure is ʕ•ᴥ•ʔ

Buzzword

Blockchain has become a buzzword that is often used in a way that only confuses newcomers. You'll find definitions in the wild like, "a blockchain is a digital ledger in which transactions made in a cryptocurrency are recorded chronologically and publicly." That is correct, but... do you know what it is yet? I didn't.

Most often it is used to refer to some platform or decentralized application (dapp), but a blockchain is really just an immutable data structure. Tokens, coins, dapps, etc. are built using this data structure. This data structure is mainly used to distribute a ledger of transactions to every participant in the network. It is a series of records that are linked, or chained, together. What these records store is transaction data. The transactions are verifiable by anybody who has the data and/or the application to use that data, due to the way the data structure works.

So, the word itself changes meaning based on context, whether it be the micro data structure or the macro network of decentralized ledgers. The data structure itself is the basic unit of all of this crypto-madness and that is the context of this post.

Building blocks

It helps me to flesh out abstract concepts by taking something apart and putting it back together. In doing so with a few repos that leverage a blockchain data structure, I thought it would prove useful to others if I made a simple one in Ruby. Hopefully, this post will help reify the concept of a blockchain through code.

Let's create a Block (this will all be done in Ruby, but you shouldn't have any problem following along regardless of your programming background):

class Block
  attr_reader :index, :parent, :created_at, :data, :hash

  def initialize(index:, data:, parent: '')
    @index         = index.to_i
    @data          = data
    @parent        = parent.empty? ? '0' : parent
    @created_at    = Time.now.to_s
    @hash          = ''
  end
end

A Block is just something that stores data and some essential metadata. It's really that simple. Our Block class contains some data, an index, a reference to a parent block, a created_at date, and a hash. These properties will all be instantiated whenever we create a new block object.

A key component to these blocks, and something we've purposefully glossed over to this point, is their immutability. Every block gets a cryptographic hash applied to it. Every protocol has its own way of applying this hash, but we're not so interested in how it gets applied in our little proof-of-concept. We're just gonna use Ruby's standard Digest class and slap a hash onto a block when it gets instantiated.

class Block
  ...
  def initialize(index:, data:, parent: '')
     ...
    @hash          = hashsum
  end

  private

  def hashsum
    hashable = "#{index.to_s} #{parent} #{created_at} #{data.to_s}"
    Digest::SHA2.new(256).hexdigest(hashable)
  end
end

hashsum is just a private method that takes the index from the block currently being created, the parent hash, the created at date, and data and feed that to Ruby's Digest::SHA2(256).hexdigest. Trying it out yields results that look like this:

(main)> Block.new(index: 0, data: 'your mom')
=> #<Block:0x00007ff6c4cf1f80
 @created_at="2018-05-28 17:33:03 -0700",
 @data="your mom",
 @hash="ae8f611206e621c3a50cdb695c58adda78b3432986ed0f8dd4e1246456c332a2",
 @index=0,
 @parent="0">
(main)> Block.new(index: 1, data: 'your dad', parent: _.hash)
=> #<Block:0x00007ff6c477c5f0
 @created_at="2018-05-28 17:34:27 -0700",
 @data="your dad",
 @hash="981acd98146a22d724524df236fb57161dec013c9820d683d098d5c05880852e",
 @index=1,
 @parent="ae8f611206e621c3a50cdb695c58adda78b3432986ed0f8dd4e1246456c332a2">

We can now create blocks! What's more our blocks know about each other. Notice that our second block stores a reference to its parent block by storing the parent's hash value. Now we just need a convenient wrapper to chain them altogether, as well as provide some accessors and validators.

We'll do this by creating a new class Blockchain which will store a series of blocks:

class Blockchain
  def initialize
     @chain = []
  end   
end

Simple enough, but we'll want an easy way to push new blocks into this chain. Let's add a method that will take arbitrary data for storage, calculate the position of the newly created block, create it and push it onto the blockchain. This isn't very SOLID code but we're hurrying to finish our proof-of-concept (PoC) and can always refactor this later.

class Blockchain
  ...
  # not very SOLID but this just a PoC
  def add_block(data)
    chain << Block.new(index: chain.size, data: data, parent: last_hash)
  end

  def last_hash
    chain.last&.hash || ''
  end

  private

  attr_reader :chain
end

Trying it out in pry works like a charm:

(main)> load 'blockchain.rb'
=> true
(main)> bc = Blockchain.new
=> #<Blockchain:0x00007fe248878638 @chain=[]>
(main)> bc.add_block({ start_over: true })
=> [#<Block:0x00007fe248bc8770
  @created_at="2018-05-28 17:51:44 -0700",
  @data={:start_over=>true},
  @hash="a52c05c50d0a024acbb965f5d7f78fddcd54166b7154dfc487fd2f54d428a208",
  @index=0,
  @parent="0">]
(main)> bc.add_block({ start_over: false })
=> [#<Block:0x00007fe248bc8770
  @created_at="2018-05-28 17:51:44 -0700",
  @data={:start_over=>true},
  @hash="a52c05c50d0a024acbb965f5d7f78fddcd54166b7154dfc487fd2f54d428a208",
  @index=0,
  @parent="0">,
 #<Block:0x00007fe245635950
  @created_at="2018-05-28 17:51:51 -0700",
  @data={:start_over=>false},
  @hash="a159d1e698518af46f82938c2f7e830a80d16e527a1e667fdd298417004f525e",
  @index=1,
  @parent="a52c05c50d0a024acbb965f5d7f78fddcd54166b7154dfc487fd2f54d428a208">]

Et voila! The meat of our blockchain is now implemented! No blockchain would be complete without the ability to validate its integrity. So, let's add a quick valid? method which will loop thru all the blocks on the chain and make sure the hash values match and that each child has the proper parent. If this method ever fails, our structure's immutability has been compromised and is a very bad thing.

class Blockchain
  ...
  def valid?
    return true if chain.size <= 1
    link = chain.each # coerce to an enumerator
    loop do           # loops rescue StopIteration errors
      previous = link.next
      return false if previous.hash != link.next.parent
    end
    return true
  end

  def last
    chain.last
  end

  def size
    chain.size
  end
...
end

With this simple validator in place we really only have some a few convenient frills to add. I'd like a welcome message and a base block to be instantiated whenever a new blockchain object is created. Let's take care of that now to wrap this up:

class Blockchain
  def initialize
    welcome
    @chain = []
    add_first_block!
  end

  ...
  private
  ...
  def add_first_block!
    chain << Block.new(index: 0, data: 'Genenis Block')
  end

  def welcome
    puts <<~BLCKCHN
      Welcome, to Blockchain!
      To add to the chain, call `#add_block` and pass in a data\n\n
    BLCKCHN
  end
end

We have created two private methods that will be invoked whenever a new blockchain is created (in the real world, your blockchain should only every be created one time). We'll print a welcome message to the screen and create the first block of the chain. There you have it, a simple but functional blockchain data structure! The finished product is well under one hundred lines of code.

This is by no means ready for any kind of production application. You will want additional safe guards against tampering, and robust authentication etc. but I hope this has been a helpful introduction to how this data structure works. With thousands of applications already in use the blockchain isn't going away, but as you can see it is really nothing to be afraid of and isn't even terribly novel. Until next time!

༼ ºل͟º ༼ ºل͟º ༼ ºل͟º ༽ ºل͟º ༽ ºل͟º ༽