A Rudimentary Blockchain Written in Crystal Part 1
So, what is a blockchain? It’s a list of blocks linked and secured by cryptographic hashes.
Blockchains have become more practical today due to the reduced sized of and increased amount of space in hard drives.
Not too long ago, it was a lot less practical. Each full node on the Bitcoin network will have a copy of the ENTIRE blockchain (which is something like 150GB+)! The reason for that massive size is due to the chain storing every transaction that has ever occurred since it's inception.
Building 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 many different hashing algorithms, but for this project, I will be using SHA256, which is the one used in Bitcoin.
Each block is stored with a timestamp and an index.
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).
block.cr
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
This file will create all of our blocks. Each block contains the following data:
- index: indicates the index of the block ex: 0, 1, 2 , 3, etc.
- timestamp: timestamp in epoch, number of seconds since 1 Jan 1970
- data: the actual data that needs to be stored on the blockchain.
- previous_hash: the hash of the previous block, this is the chain/link between the blocks
- nonce: this is the number that is to be mined/found.
- current_hash: The hash value of the current block, this is generated by combining all the above attributes and passing it through our hashing algorithm
Also, in this block of code, the self.first
method starts the blockchain and generates the genesis block of said chain like so:
#CrystalChain::Block:0x10b13ac80
@current_hash="acb701a9b75a061888910d34df8a7155a8c888910d34df692db92355964d54e",
@data="Genesis Blockerinooo", @index=0, @timestamp=2020-07-13 17:54:02 +03:00, @previous_hash="0"
After the first method runs, all other blocks are created by the next
method.
By storing the previous hash of each block, a block can’t be modified without changing the hash of every consecutive block.
If the data in a block is changed, all hashes of the future blocks must be changed as well. This is because the hash of the block depends on the value of the previous hash of the previous block.
These hashes act as a cryptographic proof and helps ensure that once a block is added to the blockchain it cannot be replaced or removed.
That concludes the first post of this blockchain series. In the next post I will be going over the proof of work and how the blocks are mined.
If you are interested in checking out the code and/or playing around with it, you can find it on my GitHub at the link below:
https://github.com/nolyoi/crystal-chain
Original post from my blog: https://nolanm.dev/posts/10-a-rudimentary-blockchain-written-in-crystal