loading...

A Rudimentary Blockchain Written in Crystal Pt. 1

nolyoi profile image Nolan Mayersky ・2 min read

So, what is a blockchain? It’s a list (chain) of blocks linked and secured by digital fingerprints (also known as crypto hashes).

The easiest way to think of it is as a linked list data structure. That being said, a linked list only required to have a reference to the previous element; a block must have an identifier depending on the previous block’s identifier, meaning that you cannot replace a block without recomputing every single block that comes after.

For now, think of blockchain as a series of blocks with some data linked with a chain, the chain being the hash of the previous block.

Blockchains have become more practical today due to the reduced sized of and increased amount of space in hard drives. A few decades ago, not so much. Each full node on the Bitcoin network will have a copy of the entire blockchain (150GB+)! That is a copy of every block ever mined over the last 11 years.

On to CrystalChain

I'm going to write this as a brief run-through of the code and how a blockchain's core structure is set up.

There are different hashing algorithms, and for this project, I chose SHA256, which is the one used in Bitcoin.

Each block is stored with a timestamp and an index. In theory, you only need one or the other. In CrystalChain, we’re going to store both. To help ensure integrity throughout the blockchain, each block will have a self-identifying hash.

Like Bitcoin, each block’s hash will be a cryptographic hash of the block’s (index, timestamp, data, and the hash of the previous block’s hash previous_hash). The data can be anything you want for now.

block.cr

require "openssl"
require "./proof_of_work"
require "./transaction"
require "json"

module CrystalChain
  class Block
    include ProofOfWork
    include JSON::Serializable
    property current_hash : String, index : Int32, 
             nonce : Int32, previous_hash : String

    def initialize(index = 0, 
                   data = "data", 
                   transactions = [] of Transaction, 
                   previous_hash = "hash")
      @data = data
      @index = index
      @timestamp = Time.utc
      @previous_hash = previous_hash
      @nonce = proof_of_work
      @current_hash = calc_hash_with_nonce(@nonce)
      @transactions = transactions
    end

    def self.first(data = "Genesis Block")
      Block.new(data: data, previous_hash: "0")
    end

    def self.next(previous_block, transactions = [] of Transaction)
      Block.new(
        transactions: transactions,
        index: previous_block.index + 1,
        previous_hash: previous_block.current_hash
      )
    end

    private def hash_block
      hash = OpenSSL::Digest.new("SHA256")
      hash.update("#{@index}#{@timestamp}#{@data}#{@previous_hash}")
      hash.final.hexstring
    end

    def recalculate_hash
      @nonce = proof_of_work
      @current_hash = calc_hash_with_nonce(@nonce)
    end

  end
end

Follow the rest of this post on my blog @
https://nolanm.dev/posts/10-a-rudimentary-blockchain-written-in-crystal

Enjoy!

Posted on by:

nolyoi profile

Nolan Mayersky

@nolyoi

I'm a 30 (oh, wow, I'm that old now) year old software engineer from Northwest, Indiana. Looking to meet like-minded people. Let's become friends and build together?

Discussion

pic
Editor guide