In this article, we'll explore how to build a simple working blockchain demo using ** Ruby **.
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
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
After a while, only four nodes get the peer-end information and the data keeps changing. This is a simple Gossip network.
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 **
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.
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
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