How to build the simplest blockchain in Ruby

In this article, we'll explore how to build a simple working blockchain demo using ** Ruby **.

Stage 1: Remittance

At this stage, we will check the balance and make the transfer. Remittances are additions or subtractions that are made based on your account balance.

The HTTP protocols GET and POST are the best way to implement this feature. GET gets the data from the server and POST modifies the data on the server.

Here, the UI display does not require the HTML protocol. You can use the Ruby web framework Sinatra to organize URLs and related methods, and use the UE to see the transfer information on the command line.

Client-side methods and server-side URLs are very simple.

Client: client.rb

def create_user(name) … end

  def get_balance(user)  … end

  def transfer(from, to, amount) ... end

Server: hasebcoin.rb

get "/balance" ... end

  post "/users" ... end

  post "/transfers" ... end

Knowledge required for this layer: ruby, HTTP GET, POST, Sinatra

Stage 2: Building a gossip network

The blockchain has a decentralized structure called the "gossip protocol". "Gossip" here is not a rumor, but information that is spread over a distributed network.

Let's build a gossip network where movie names are exchanged.

client.rb sends a message to the specified port.

def self.gossip(port, state)
  ...  

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

end

gossip.rb receives two parameters, a source port and a destination port. Exchanges information through specific ports on the source side, such as ports 1111 and 2222.

In a real distributed network, the two ports are essentially two network nodes. Exchanging information between different local ports represents communication between different nodes in the simulated network.

At each node Speak the name of your favorite movie every 3 seconds.

every(3.seconds) do

  …

  gossip_response = Client.gossip(port, JSON.dump(STATE))

  update_state(JSON.load(gossip_response))

  ...

end

Change your favorite movie name every 8 seconds.

every(8.seconds) do

  …

  update_state(PORT => [@favorite_movie, @version_number])

  ...

end

The server receives and processes the data.

post '/gossip' do

  …

  update_state(JSON.load(their_state))

  …

end

In a network of 4 people

  1. Run gossip.rb 1111 on the first node. The first node speaks the name of your favorite movie on port 1111. 2, run gossip.rb 2222 1111. The second node speaks your favorite movie name on port 2222 to the first node (port 1111). 3, run gossip.rb 3333 2222. The third node speaks your favorite movie name from port 3333 to the second node (port 2222). 4, run gossip.rb 4444 3333. The fourth node speaks your favorite movie name from port 4444 to the third node (port 3333).

After a while, only four nodes get the peer-end information and the data keeps changing. This is a simple Gossip network.

Stage 3: Data encryption and decryption

Top-level cryptographic algorithms are the foundation of blockchain. At this layer, asymmetric encryption technology is used to implement blockchain accounts. The RSA algorithm can generate public and private keys and force asymmetric encryption.

def generate_key_pair … end
def sign(plaintext, raw_private_key) ... end

Thanks to the OpenSSL module in the Ruby language, you can quickly implement asymmetric encryption and signature verification. On the blockchain, the public key is the account and the private key is the password. Each key pair will be one blockchain account.

Decrypt the ciphertext.

def plaintext(ciphertext, raw_public_key) … end

Check if the ciphertext is a message.

def valid_signature?(message, ciphertext, public_key) … end

** Knowledge required for this layer: Asymmetric encryption algorithm **

Stage 4: Data mining

At this stage, the proof of work is implemented and blocks are generated for the blockchain. This is a time consuming and tedious process. Hash functions are irreversible and there are no conflicts. The calculation process is simple. You can get the result just by performing a hash operation on the input.

The input is information about the remittance, such as the remittance amount, the sender's name, and the recipient's name. There are various algorithms for hash operations.

Here we use the SHA256 algorithm.

def hash(message) … end

If you hash the same information, you will get different results each time. The operation is continued until the obtained result satisfies the feature such as "starting from several digits of 0".

Check if the result starts with a few digits of 0.

def is_valid_nonce?(nonce, message)

  hash(message + nonce).start_with?("0" * NUM_ZEROES)

end

It is not easy to carry out work to satisfy the above conditions. It consumes a lot of time. All such work is called mining.

def find_nonce(message)

  …  

  until is_valid_nonce?(nonce, message)

  ...

end

The input contains the result of the previous hash operation. Therefore, each hash operation is affected by the previous hash operation. In other words, this is a chain structure. This is the reason why it is called a blockchain.

Stage 5: Longest chain rule

At this stage, the first block is initialized, the blockchain structure is generated accordingly, and the blockchain is formed. The blockchain is stored in an Array structure. During saving, the block must undergo validation.

Initialize the block.

def initialize(prev_block, msg)

  @msg = msg

  @prev_block_hash = prev_block.own_hash if prev_block
  
  mine_block!
    
end

The most rewarding task during mining is finding nonces.

def mine_block!

  @nonce = calc_nonce

  @own_hash = hash(full_block(@nonce))

end

The complete block is compressed this way.

def full_block(nonce)

  [@msg, @prev_block_hash, nonce].compact.join

end

Initialize the blockchain: class BlockChain

Just save using Array!

def initialize(msg)
  
  @blocks = []

  @blocks << Block.new(nil, msg)

end

Add blocks to the chain. The entire blockchain is growing continuously.

def add_to_chain(msg)

  @blocks << Block.new(@blocks.last, msg)

  puts @blocks.last

end

You need to rigorously verify that the block is healthy.

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. Combination of pieces

Finally, Blockchain works its magic through harmonious collaboration with all the components in the network. In the first stage, the transfer is a transaction class and you need to use the private key to sign the information.

@signature = PKI.sign(message, priv_key)

The miner's reward for getting the first block is 500,000 silver coins.

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

Check if the spending charged to your account is valid.

def all_spends_valid?

  compute_balances do |balances, from, to|

    return false if balances.values_at(from, to).any? { |bal| bal < 0 }

  end

  true

end

Add an unknown node $ PEERS to keep the network growing.

if PEER_PORT.nil?

  # You are the progenitor!

  $BLOCKCHAIN = BlockChain.new(PUB_KEY, PRIV_KEY)

  else

  # You're just joining the network.

  $PEERS << PEER_PORT

end

Data processing between nodes loads and updates the blockchain and PEER.

# @param blockchain

# @param peers

post '/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

The processing of the received block focuses on whether the chain is long.

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

Update PEER until new.

def update_peers(their_peers)

  $PEERS = ($PEERS + their_peers).uniq

end

When sending money, get the recipient's pub_key and send the money via the sender's pub_key.

# @param to (port_number)

# @param amount

post '/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

Put the blockchain into the gossip network and assemble all the functional components. That's all there is to it. You have successfully created a blockchain.

More information about this demo can be found on Github: [https://github.com/Haseeb-Qureshi/lets-build-a-blockchain](https://github.com/Haseeb-Qureshi/lets- build-a-blockchain? spm = a2c65.11461447.0.0.30084c44XBVTHc)

For more information on blockchain and other innovative technologies, please visit www.alibabacloud.com.

Recommended Posts

How to build the simplest blockchain in Ruby
How to iterate infinitely in Ruby
How to install Bootstrap in Ruby
How to retrieve the hash value in an array in Ruby
How to get date data in Ruby
How to get the date in java
How to install the language used in Ubuntu and how to build the environment
How to find the cause of the Ruby error
How to add sound in the app (swift)
How to build android-midi-lib
How to debug the processing in the Ruby on Rails model only on the console
[Ruby on Rails] How to install Bootstrap in Rails
How to build an executable jar in Maven
[Ruby] How to prevent errors when nil is included in the operation
How to check Rails commands in the terminal
How to implement Pagination in GraphQL (for ruby)
I want to get the value in Ruby
[Ruby basics] How to use the slice method
[Ruby] Learn how to use odd? Even? And count the even and odd numbers in the array!
How to resolve errors that occur in the "Ruby on Rails" integration test
[Ruby] How to use standard output in conditional branching
How to set the display time to Japan time in Rails
[Java] How to omit the private constructor in Lombok
[Ruby] How to find the sum of each digit
[Ruby on Rails] How to change the column name
Organized how to interact with the JDK in stages
[Ruby On Rails] How to reset DB in Heroku
How to launch another command in a Ruby program
How to specify the resource path in HTML import
[Ruby] How to get the tens place and the ones place
[Rails] How to display an image in the view
How to resolve SSL_connect error in PayPal Ruby SDK
How to use Ruby return
[Ruby] How to comment out
Ruby: How to use cookies
[Ruby] How to write blocks
Offline real-time how to write Implementation example of the problem in E05 (ruby, C11)
How to get the class name / method name running in Java
How to correctly check the local HTML file in the browser
How to use the getter / setter method (in object orientation)
How to set chrony when the time shifts in CentOS7
How to connect the strings in the List separated by commas
How to change a string in an array to a number in Ruby
How to create a placeholder part to use in the IN clause
[With back tricks] How to introduce React to the simplest Rails
What I did in the version upgrade from Ruby 2.5.2 to 2.7.1
How to display a graph in Ruby on Rails (LazyHighChart)
[Ruby] How to retrieve the contents of a double hash
How to add the same Indexes in a nested array
How to derive the last day of the month in Java
How to disable existing selected items in the select box
How to switch Java in the OpenJDK era on Mac
[Rails] How to display information stored in the database in view
[Ruby] How to batch convert strings in an array to numbers
How to use Lombok in Spring
How to find May'n in XPath
How to hide scrollbars in WebView
How to use the form_with method
How to run JUnit in Eclipse
Pass the i18n locale to JavaScript
Try to implement Yubaba in Ruby