A Rudimentary Blockchain Written in Crystal Pt. 1
Nolan Mayersky
Posted on July 23, 2020
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 July 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.