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 build an executable jar in Maven
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 on Rails] How to change the column name
[Rails] How to display an image in the view
How to resolve SSL_connect error in PayPal Ruby SDK
[Rails] How to display information stored in the database in view
Pass the i18n locale to JavaScript
How to master programming in 3 months
How to use Ruby inject method
How to build CloudStack using Docker
How to concatenate strings in java
How to install Swiper in Rails
[For beginners] How to get the Ruby delayed railway line name
Things to remember and concepts in the Ruby on Rails tutorial
I want to change the value of Attribute in Selenium of Ruby
Measure the bottleneck! How to trace only slow methods in AspectJ
How to call multiple names at once in the same category
How to get the length of an audio file in java
How to increment the value of Map in one line in Java
Studying how to use the constructor (java)
How to use environment variables in RubyOnRails
How to implement asynchronous processing in Outsystems
[Ruby] I tried to summarize the methods that frequently appear in paiza ②
How to publish a library in jCenter
Android development, how to check null in the value of JSON object
[Ruby] Returns characters in a pyramid shape according to the entered numbers
How to specify id attribute in JSF
Ruby: CSV :: How to use Table Note
Summarized how to climb the programming stairs
How to overwrite Firebase data in Swift
How to use credentials.yml.enc introduced in Rails 5.2
[Rails] How to apply the CSS used in the main app with Administrate
Java-database connection Java-MySQL connection ③-2: How to set CLASSPATH to the build bus of Eclipse (Pleiades All in One) / September 2017
How to assemble JSON directly in Jackson
How to reference a column when overriding the column name method in ActiveRecord
How to insert processing with any number of elements in iterative processing in Ruby
[For beginners] How to debug in Eclipse
How to create your own annotation in Java and get the value
How to build Rails 6 environment with Docker
How to use ExpandableListView in Android Studio
How to display error messages in Japanese
How to check the latest version of io.spring.platform to describe in pom.xml of Spring (STS)
[Rails] How to operate the helper method used in the main application with Administrate
How to start a subscript from an arbitrary number in Ruby iterative processing
How to hide null fields in response in Java
How to define multiple orm.xml in Spring4, JPA2.1
[Java] Memo on how to write the source
How to write Java String # getBytes in Kotlin?
[ruby] How to receive values from standard input?
[Rails] How to use PostgreSQL in Vagrant environment
[Spring Boot] How to refer to the property file
Ruby How to convert between uppercase and lowercase
Notes on how to write comments in English
Implement the algorithm in Ruby: Day 2 -Bubble sort-
How to automatically generate a constructor in Eclipse
[Java] How to display the day of the week acquired by LocalDate, DateTimeformatter in Japanese
Summary of how to use the proxy set in IE when connecting with Java
[Rails] How to display the weather forecast of the registered address in Japanese using OpenWeatherMap