Building the Simplest Blockchain with Ruby

Stage 1: Money Transfer

def create_user(name) … end  def get_balance(user)  … end  def transfer(from, to, amount) ... end
get "/balance" ... end  post "/users" ... end  post "/transfers" ... end

Stage 2: Building a Gossip Network

def self.gossip(port, state)
...
Faraday.post("#{URL}:#{port}/gossip", state: state).body

...
end
every(3.seconds) do  gossip_response = Client.gossip(port, JSON.dump(STATE))  update_state(JSON.load(gossip_response))  ...end
every(8.seconds) do  update_state(PORT => [@favorite_movie, @version_number])  ...end
post '/gossip' do  update_state(JSON.load(their_state))end

Stage 3: Data Encryption and Decryption

def generate_key_pair … end
def sign(plaintext, raw_private_key) ... end
def plaintext(ciphertext, raw_public_key) … end
def valid_signature?(message, ciphertext, public_key) … end

Stage 4: Data Mining

def hash(message) … end
def is_valid_nonce?(nonce, message)  hash(message + nonce).start_with?("0" * NUM_ZEROES)end
def find_nonce(message)  until is_valid_nonce?(nonce, message)  ...end

Stage 5: The Longest Chain Rule

def initialize(prev_block, msg)  @msg = msg  @prev_block_hash = prev_block.own_hash if prev_block

mine_block!

end
def mine_block!  @nonce = calc_nonce  @own_hash = hash(full_block(@nonce))end
def full_block(nonce)  [@msg, @prev_block_hash, nonce].compact.joinend
def initialize(msg)

@blocks = []
@blocks << Block.new(nil, msg)end
def add_to_chain(msg)  @blocks << Block.new(@blocks.last, msg)  puts @blocks.lastend
def valid?  @blocks.all? { |block| block.is_a?(Block) } &&    @blocks.all?(&:valid?) &&

@blocks.each_cons(2).all? { |a, b| a.own_hash == b.prev_block_hash }

end

Stage 6: Combining the Pieces

@signature = PKI.sign(message, priv_key)
def self.create_genesis_block(pub_key, priv_key)  genesis_txn = Transaction.new(nil, pub_key, 500_000, priv_key)  Block.new(nil, genesis_txn)end
def all_spends_valid?  compute_balances do |balances, from, to|    return false if balances.values_at(from, to).any? { |bal| bal < 0 }  end  trueend
if PEER_PORT.nil?  # You are the progenitor!  $BLOCKCHAIN = BlockChain.new(PUB_KEY, PRIV_KEY)  else  # You're just joining the network.  $PEERS << PEER_PORTend
# @param blockchain# @param peerspost '/gossip' do  their_blockchain = YAML.load(params['blockchain'])  their_peers = YAML.load(params['peers'])  update_blockchain(their_blockchain)  update_peers(their_peers)    YAML.dump('peers' => $PEERS, 'blockchain' => $BLOCKCHAIN)end
def update_blockchain(their_blockchain)    return if their_blockchain.nil?  return if $BLOCKCHAIN && their_blockchain.length <= $BLOCKCHAIN.length

return unless their_blockchain.valid? $BLOCKCHAIN = their_blockchain

end
def update_peers(their_peers)  $PEERS = ($PEERS + their_peers).uniqend
# @param to (port_number)# @param amountpost '/send_money' do  to = Client.get_pub_key(params['to'])  amount = params['amount'].to_i  $BLOCKCHAIN.add_to_chain(Transaction.new(PUB_KEY, to, amount, PRIV_KEY))  'OK. Block mined!'
end

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store