I have a small (formerly) ruby blockchain script I'm trying to convert over into Crystal, that looks like this so far:
# build your own blockchain from scratch in crystal!
#
# to run use:
# $ crystal ./blockchain_with_proof_of_work.cr
require "openssl" # for hash checksum digest function SHA256
class Block
getter index : Int32
getter timestamp : Time
getter data : String
getter previous_hash : String
getter nonce : Int32 # # proof of work if hash starts with leading zeros (00)
getter hash : String
def initialize(index, data, previous_hash)
@index = index
@timestamp = Time.now
@data = data
@previous_hash = previous_hash
@nonce, @hash = compute_hash_with_proof_of_work
end
def compute_hash_with_proof_of_work(difficulty = "00")
nonce = 0
loop do
hash = calc_hash_with_nonce(nonce)
if hash.starts_with?(difficulty)
return [nonce, hash] # # bingo! proof of work if hash starts with leading zeros (00)
else
nonce += 1 # # keep trying (and trying and trying)
end
end
end
def calc_hash_with_nonce(nonce = 0)
sha = OpenSSL::Digest.new("SHA256")
sha.update(nonce.to_s + @index.to_s + @timestamp.to_s + @data + @previous_hash)
sha.hexdigest
end
def self.first(data = "Genesis") # create genesis (big bang! first) block
# # uses index zero (0) and arbitrary previous_hash ("0")
Block.new(0, data, "0")
end
def self.next(previous, data = "Transaction Data...")
Block.new(previous.index + 1, data, previous.hash)
end
end # class Block
#####
# # let's get started
# # build a blockchain a block at a time
b0 = Block.first("Genesis")
b1 = Block.next(b0, "Transaction Data...")
b2 = Block.next(b1, "Transaction Data......")
b3 = Block.next(b2, "More Transaction Data...")
blockchain = [b0, b1, b2, b3]
puts blockchain
######
# will print something like:
#
# [#<Block:0x1e204f0
# @data="Genesis",
# @hash="00b8e77e27378f9aa0afbcea3a2882bb62f6663771dee053364beb1887e18bcf",
# @index=0,
# @nonce=242,
# @previous_hash="0",
# @timestamp=2017-09-20 20:13:38 +0200>,
# #<Block:0x1e56e20
# @data="Transaction Data...",
# @hash="00aae8d2e9387e13c71b33f8cd205d336ac250d2828011f5970062912985a9af",
# @index=1,
# @nonce=46,
# @previous_hash=
# "00b8e77e27378f9aa0afbcea3a2882bb62f6663771dee053364beb1887e18bcf",
# @timestamp=2017-09-20 20:13:38 +0200>,
# #<Block:0x1e2bd58
# @data="Transaction Data......",
# @hash="00ea45e0f4683c3bec4364f349ee2b6816be0c9fd95cfd5ffcc6ed572c62f190",
# @index=2,
# @nonce=350,
# @previous_hash=
# "00aae8d2e9387e13c71b33f8cd205d336ac250d2828011f5970062912985a9af",
# @timestamp=2017-09-20 20:13:38 +0200>,
# #<Block:0x1fa8338
# @data="More Transaction Data...",
# @hash="00436f0fca677652963e904ce4c624606a255946b921132d5b1f70f7d86c4ab8",
# @index=3,
# @nonce=59,
# @previous_hash=
# "00ea45e0f4683c3bec4364f349ee2b6816be0c9fd95cfd5
However when I run it I get an error that states:
Error in blockchain.cr/blockchain_with_proof_of_work.cr:57: instantiating
'Block:Class#first(String)'
b0 = Block.first("Genesis")
^~~~~
in blockchain.cr/blockchain_with_proof_of_work.cr:45: instantiating
'Block:Class#new(Int32, String, String)'
Block.new(0, data, "0")
^~~
in blockchain.cr/blockchain_with_proof_of_work.cr:22: instance variable
'@nonce' of Block must be Int32, not (Int32 | String)
@nonce, @hash = compute_hash_with_proof_of_work
^~~~~~