{getToc} $title={Table of Contents}
Introduction:
Hello everyone! 😊, welcome back to our blockchain technology tutorial series. In the first part #1, we covered the fundamentals and benefits of blockchain technology. We
also discussed some of the real-world applications and examples of
blockchain in various sectors such as DeFi, smart contracts, digital
identity and supply chain management. And gave you an overview of some of
the existing blockchain platforms and projects that you can check
out.
In this part #2, we will focus on the development side of blockchain
technology. And we'll show you some of the tools and frameworks that you can
use to build and interact with blockchain applications. And we also teach
you how to use programming languages such as Solidity, JavaScript, Python
etc. to code and deploy a simple blockchain application.
By the end of this part, you will have a clearer idea of how to develop
blockchain applications and what are the challenges and opportunities. So,
let’s begin!
Blockchain Development:
Now, we will introduce some of the tools and frameworks for developing
blockchain applications. And we'll also explain how to create and interact
with a blockchain using programming languages such as Solidity, JavaScript,
Python etc. And we will demonstrate how to test and deploy a simple
blockchain application.
Tools and Frameworks:
Building blockchain applications requires a combination of programming
languages, tools, frameworks and libraries. Depending on the type and
purpose of your blockchain application, you may need different tools and
frameworks to suit your needs.
Here are some of the best tools, frameworks and libraries for building blockchain applications:
-
Ethereum: the most popular and widely used blockchain development
platform in the world. It introduced a revolutionary feature known as
the smart contract which is a program that runs on the blockchain and
can execute transactions and logic according to predefined rules.
Ethereum also provides the Ethereum Virtual Machine (EVM) which is a
runtime environment that can execute smart contracts written in various
languages such as Solidity, Vyper or Serpent.
-
Hyperledger Fabric: a blockchain framework designed for creating
highly scalable and secure blockchain applications for enterprises. It
supports private and permissioned blockchains where only authorized
participants can join and access the network. And it also supports
modular architecture where different components such as consensus
algorithms, membership services or smart contract engines can be plugged
and unplugged as needed.
-
IPFS: stands for Inter Planetary File System which is a
distributed file system that can store and share data across a
peer-to-peer network. It can be used to store large files or data that
are not suitable for storing on the blockchain such as images, videos or
documents. IPFS can also provide content addressing which means that
each file or data has a unique identifier that can be used to locate it
on the network.
-
Truffle: a development environment and testing framework for
Ethereum smart contracts. It provides features such as smart contract
compilation, deployment, testing, debugging and scripting. Truffle also
integrates with other tools such as Ganache, Remix or OpenZeppelin to
provide a comprehensive development experience.
-
Web3.js: is a JavaScript library that allows developers to
interact with Ethereum nodes using HTTP or WebSocket protocols. It
provides an API to access various functions of the Ethereum blockchain
such as accounts, transactions, contracts, events or filters. Web3.js
also supports various Ethereum-compatible networks such as Mainnet,
Ropsten, Rinkeby or Kovan.
-
Ganache: is a personal blockchain that can be used for testing
and development purposes. It allows developers to create and run a local
Ethereum network with customizable settings such as block time, gas
limit or accounts. Ganache also provides a graphical user interface
(GUI) that displays the network status, transactions history, balances,
logs and more.
-
Remix: is an online IDE (Integrated Development Environment) that
allows developers to write, compile, debug and deploy smart contracts
using a web browser. It supports various languages such as Solidity or
Vyper. Remix also provides features such as syntax highlighting,
auto-completion, code analysis and testing tools.
- OpenZeppelin: a framework that provides reusable smart contract components and best practices for developers. It offers various modules and libraries for implementing common functionalities and security features in smart contracts such as ownership, access control, token standards and math operations etc.
How to Create a Smart Contract Using Solidity:
Solidity is the main programming language for writing smart contracts
for the Ethereum blockchain. It is a contract-oriented language which
means that smart contracts are responsible for storing all of the
programming logic that transacts with the blockchain. Solidity is a
high-level programming language that looks a lot like JavaScript,
Python and C++.
To create a smart contract using Solidity, we need to follow these steps:
- Define version of Solidity to use with the pragma directive.
- Define name and structure of the contract with the contract keyword.
- Define state variables and functions of the contract.
- Compile contract into bytecode and ABI using a compiler such as solc.
- Deploy contract to a blockchain network using a tool such as web3.js or truffle.
Let’s see an example of a simple smart contract that can store
and retrieve a message:
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.17 <0.9.0;
contract Message {// A state variable to store the messagestring public message;// A constructor function to initialize the messageconstructor(string memory initialMessage) {message = initialMessage;}// A function to update the messagefunction setMessage(string memory newMessage) public {message = newMessage;}// A function to get the messagefunction getMessage() public view returns (string memory) {return message;}}
In this example, we have defined a contract named Message that has one
state variable called message of type string. And we have also defined
a constructor function that takes an initial message as an argument
and assigns it to the state variable. And defined two functions: one
to set a new message and another one to get the current message. We
have used some modifiers such as public, memory and view to specify
the visibility, location and behavior of the variables and functions.
Compile
To compile this contract, we can use a tool such as Remix IDE which is
an online IDE for Solidity development. And we can create a new file
named Message.sol and paste our code there. Then click on the Solidity
compiler tab and select our file and version. And click on compile to
generate the bytecode and ABI of our contract.
Deploy
To deploy this contract, we can use a tool such as Truffle, which is a
development environment and testing framework for Ethereum smart
contracts. And we can create a new project folder and run truffle init
to initialize it. Then copy our contract file to the contracts folder
and create a migration file in the migrations folder. A migration file
is a script that tells Truffle how to deploy our contract to a
network.
Here is an example of a migration file for our contract:
//Migrations/2_deploy_message.jsconst Message = artifacts.require("Message");module.exports = function (deployer) {// Deploy the Message contract with an initial messagedeployer.deploy(Message, "Hello, world!");};
Here, we have imported our contract artifact from the build folder
and used the deployer object to deploy it with an argument for the
constructor function. To run this migration, we need to have a
network configuration in our truffle-config.js file.
For example, we can use Ganache as our local development network by
installing it with npm install -g ganache-cli and running it with
ganache-cli. And then add this configuration to our file:
// truffle-config.jsmodule.exports = {networks: {development: {host: "127.0.0.1",port: 8545,network_id: "*";},},};
Next, let's run truffle migrate to deploy our contract to our local
network. We should see something like this:
$ truffle migrateCompiling your contracts...===========================> Compiling ./contracts/Message.sol> Artifacts written to /home/user/message/build/contracts> Compiled successfully using:- solc: 0.8.10+commit.fc410830.Emscripten.clangStarting migrations...======================> Network name:
How to Test and Deploy a Blockchain Application:
After creating a smart contract using Solidity, we need to
test and deploy it to a blockchain network. Testing is
important to ensure that our smart contract works as expected
and does not contain any bugs or vulnerabilities. Deploying is
the process of sending our smart contract to a specific
address on the blockchain network where it can be accessed and
executed by other users.
There are different tools and methods for testing and
deploying a blockchain application depending on the type and
purpose of the application. For example, we can use Truffle to
test and deploy our smart contract to a local development
network such as Ganache or to a public test network such as
Ropsten or Rinkeby. We can also use Remix IDE to test and
deploy our smart contract using a web browser and an extension
such as MetaMask.
Let’s see an example of how to test and deploy our
Message smart contract using Truffle and Ganache:
1. Test our smart contract:
We need to write some test cases using a testing framework
such as Mocha or Jest. We can create a new file named
test/message.js in our project folder and write some test
cases using JavaScript and an assertion library such as
Chai.
Here is an example of a test file for our contract:
// test/message.jsconst Message = artifacts.require("Message");// Use Chai assertion libraryconst { expect } = require("chai");// Write a contract test suitecontract("Message", (accounts) => {// Define a variable to hold the contract instancelet message;// Before each test, create a new contract instancebeforeEach(async () => {message = await Message.new("Hello, world!");});// Test the constructor functionit("should initialize the message with the initial value", async () => {// Get the message value from the contractconst messageValue = await message.message();// Assert that the message value is equal to the initial valueexpect(messageValue).to.equal("Hello, world!");});// Test the setMessage functionit("should update the message with the new value", async () => {// Call the setMessage function with a new valueawait message.setMessage("Hello, blockchain!");// Get the updated message value from the contractconst messageValue = await message.message();// Assert that the message value is equal to the new valueexpect(messageValue).to.equal("Hello, blockchain!");});
2. Run our test:
We need to have Ganache running as our local development
network. And start Ganache by running ganache-cli in another
terminal window. Then run truffle test in our project folder
to execute our tests. We should see something like this:
$ truffle test
Compiling your contracts...===========================> Compiling ./contracts/Message.sol> Artifacts written to /tmp/test--21195-0x3qy9X7Z1m4n> Compiled successfully using:- solc: 0.8.10+commit.fc410830.Emscripten.clangContract: Message✓ should initialize the message with the initial value (66ms)✓ should update the message with the new value (80ms)2 passing (2s)
3. Deploy our smart contract:
We need to have a network configuration in our
truffle-config.js file. For example, we can use Ganache as
our local development network by adding this configuration
to our file:
// truffle-config.js
module.exports = {networks: {development: {host: "127.0.0.1",port: 8545,network_id: "*",},},};
4. Run our migration:
We need to have a migration file in our migrations folder. A
migration file is a script that tells Truffle how to deploy
our smart contract to a network. And I have already provided
an example of a migration file for our contract in the above
section (How to Create a Smart Contract Using Solidity).
5. Deployment:
I have already provided an example of running truffle migration to deploy our contract to our
local network (How to Create a Smart Contract Using Solidity).
How to Interact with a Deployed Smart Contract:
After deploying our smart contract to a blockchain
network, we can interact with it by using various methods
and tools. Interacting with a smart contract means calling
its functions and reading or writing its state variables.
Depending on the type and purpose of our smart contract.
We may want to interact with it from a web browser, a
mobile app, a command line interface or another smart
contract.
One of the most common ways to interact with a deployed
smart contract is using a web browser and an extension
such as MetaMask. It is a browser extension that allows
users to connect to Ethereum-compatible networks and
manage their accounts and transactions. MetaMask also
provides a web3.js API that allows web developers to
interact with smart contracts using JavaScript.
To interact with our Message smart contract using MetaMask and web3.js we need to follow these steps:
- Install MetaMask on our browser and create or import an account.
- Connect MetaMask to the network where we deployed our smart contract (eg, Ganache or Ropsten).
- Get the address and ABI of our deployed smart contract.
- Create a web page that can load web3.js and communicate with MetaMask.
- Create an instance of our smart contract using web3.js and call its functions.
Let’s see an example of a simple web page that can interact with our Message smart contract:
<!-- index.html -->
<html><head><title>Message Dapp</title><!-- Load web3.js from CDN --><script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script></head><body><h1>Message Dapp</h1><p id="status">Loading...</p><p id="message"></p><input id="input" type="text" placeholder="Enter new message" /><button id="button">Update message</button><script>// Define the address and ABI of the deployed smart contractconst contractAddress = "0x123456789abcdef0123456789abcdef012345678";const contractABI = [{constant: true,inputs: [],name: "message",outputs: [{name: "",type: "string"},],payable: false,stateMutability: "view",type: "function"},{constant: false,inputs: [{name: "newMessage",type: "string",},],name: "setMessage",outputs: [],payable: false,stateMutability: "nonpayable", type: "function"},{inputs: [{name: "initialMessage", type: "string"},],payable: false,stateMutability: "nonpayable",type: "constructor"},];// Define some variables to hold the elementslet status = document.getElementById("status");let message = document.getElementById("message");let input = document.getElementById("input");let button = document.getElementById("button");// Define a variable to hold the web3 instancelet web3;// Define a variable to hold the contract instance let contract;// Define a variable to hold the user accountlet account;// Define a function to initialize the web3 instanceasync function initWeb3() {// Check if MetaMask is installed and enabledif (window.ethereum) {// Create a new web3 instance using MetaMask providerweb3 = new Web3(window.ethereum);try {// Request account access from MetaMaskawait window.ethereum.enable();// Get the user account from MetaMaskaccount = (await web3.eth.getAccounts())[0];// Update the status messagestatus.innerHTML = "Connected";} catch (error) {// Handle user rejection or any other errorconsole.error(error);status.innerHTML = "Rejected or Error";}} else {// Handle the case where MetaMask is not installedconsole.error("MetaMask not found");status.innerHTML = "MetaMask not found";}}// Define a function to initialize the contractasync function initContract() {// Create a new contract instance using the address and ABIcontract = new web3.eth.Contract(contractABI, contractAddress);// Update the status messagestatus.innerHTML = "Contract loaded";}// Define a function to get the message from the contractasync function getMessage() {// Call the message function of the contractconst messageValue = await contract.methods.message().call();// Update the message element with the valuemessage.innerHTML = messageValue;}// Define a function to update the message in the contractasync function updateMessage() {// Get the input value from the elementconst newMessage = input.value;// Check if the input is not emptyif (newMessage) {// Call the setMessage function of the contract with the new valueawait contract.methods.setMessage(newMessage).send({ from: account});// Update the status messagestatus.innerHTML = "Message updated";// Clear the input valueinput.value = "";// Get the updated message from the contractgetMessage();} else {// Update the status messagestatus.innerHTML = "Please enter a message";}}// Define a function to add an event listener to the buttonfunction addListener() {// Add a click event listener to the button elementbutton.addEventListener("click", updateMessage);}// Define an async function to initialize the appasync function initApp() {// Initialize web3await initWeb3();// Initialize contractawait initContract();// Get message from contractawait getMessage();// Add listener to buttonaddListener();}// Call the initApp function when the window loadswindow.addEventListener("load", initApp);</script></body></html>
In this example we have created a simple web page that
can display and update the message stored in our smart
contract. We have used web3.js to create a web3 instance
using MetaMask provider, a contract instance using our
address and ABI and call our contract functions using web3
contract methods. And then we have used some HTML elements
and JavaScript functions to create a basic user interface
and logic.
To run this web page, we need to serve it using a
local server such as http-server. We can install it
using npm: npm install -g http-server
Then, we can run it in our project folder:
http-server.
We should see something like this:
Starting up http-server, serving .Available on:http://127.0.0.1:8080http://192.168.1.100:8080Hit CTRL-C to stop the server
Next, open our browser and go to
http://127.0.0.1:8080/index.html.
You will see that our web page is connected to MetaMask
and displays our initial message “Hello, world!”. We can
also enter a new message in the input field and click on
the button to update it.
This is just one example of how to interact with a
deployed smart contract using MetaMask and web3.js. There
are many other ways and tools to interact with smart
contracts such as using mobile apps, command line
interfaces or other smart contracts. The main idea is to
use a provider that can connect to a blockchain network
and a library that can encode and decode smart contract
calls.
How to Create and Interact with a Blockchain using Python:
We will use the Flask framework to create a web application that
will expose our blockchain to the network. And we will use Postman
to make requests to our blockchain and test its functionality.
Create a Blockchain with Python:
To create a blockchain with Python, we will use the
following libraries:
- datetime: attach a timestamp to each block that is created or mined.
- json: encode and decode the block data before hashing it.
- hashlib: hash the block data using the SHA-256 algorithm.
- flask: create a web application that will expose our blockchain and allow us to interact with it.
Creating the Block Class:
The first step is to create a Block class that will represent
each block in our blockchain. And then we will define the
following attributes and methods for our Block class:
- init: initialize the block object with the given parameters: index, timestamp, data, previous_hash, nonce and hash. The index is the position of the block in the chain. Timestamp is the time when the block was created or mined. Data is the list of transactions in the block. The previous_hash is the hash of the previous block in the chain. the nonce is a random number used for proof-of-work. And the hash is the hash of the block data.
- calculate_hash: this method will calculate and return the hash of the block data using the SHA-256 algorithm. And use json.dumps to encode the block data into a string before hashing it.
- str: this method will return a string representation of the block object for printing purposes.
Our Block class should look like this:
import datetimeimport jsonimport hashlibclass Block:def __init__(self, index, timestamp, data, previous_hash):self.index = indexself.timestamp = timestampself.data = dataself.previous_hash = previous_hashself.nonce = 0self.hash = self.calculate_hash()def calculate_hash(self):block_string = json.dumps(self.__dict__, sort_keys=True)return hashlib.sha256(block_string.encode()).hexdigest()def __str__(self):return "Block " + str(self.index) + "\nTimestamp: " + str(self.timestamp) + "\nData: " + str(self.data) + "\nPrevious Hash: " + str(self.previous_hash) + "\nNonce: " + str(self.nonce) +"\nHash: " + str(self.hash)
Creating the Blockchain Class:
The next step is to create a Blockchain class that will
represent our blockchain. We will define the following
attributes and methods for our Blockchain class:
-
init: this method will initialize the blockchain
object with an empty list of blocks (chain) and an initial
difficulty for proof-of-work (difficulty). And create our
genesis block (the first block in the chain) by calling
the create_block method with default parameters.
-
create_block: this method will create and return a
new block object with the given parameters: proof (the
nonce value for proof-of-work) and previous_hash. And use
datetime.datetime.now to get the current timestamp and
len(self.chain) to get the index of the new block. We will
also append the new block to our chain list.
-
get_previous_block: this method will return the
last block in our chain list.
-
proof_of_work: implement the proof-of-work
algorithm to find a nonce value that satisfies the
difficulty condition. The difficulty condition is that
the hash of the block data must start with a certain
number of zeros which is determined by the difficulty
attribute. And use a while loop to increment the nonce
value until we find a valid hash. And return the nonce
value as the proof.
-
is_valid_proof: check if a given proof (nonce
value) is valid for a given block and difficulty. And
then create a copy of the block object and assign the
proof to its nonce attribute. Then we will calculate the
hash of the block data and compare it with the
difficulty condition. And return True if the hash is
valid and False otherwise.
-
is_chain_valid: check if our chain is valid by
iterating over each block and verifying its hash and
proof. We will use a for loop to go through each block
in our chain list. Starting from the second block (the
first block is the genesis block which we assume to be
valid). For each block, we will check if its
previous_hash matches the hash of the previous block and
if its proof is valid according to the proof_of_work
method. And return False if any of these checks fail and
True otherwise.
Our Blockchain class should look like this:
class Blockchain:def __init__(self):self.chain = []self.difficulty = 4self.create_block(proof=1, previous_hash='0')def create_block(self, proof, previous_hash):block = Block(index=len(self.chain),timestamp=datetime.datetime.now(), data="Some data", previous_hash=previous_hash) block.nonce = proofblock.hash = block.calculate_hash()self.chain.append(block)return blockdef get_previous_block(self):return self.chain[-1]def proof_of_work(self, block):block.nonce = 0while not self.is_valid_proof(block, self.difficulty):block.nonce += 1return block.noncedef is_valid_proof(self, block, difficulty): return block.hash.startswith('0' * difficulty)def is_chain_valid(self):for i in range(1, len(self.chain)):current_block = self.chain[i]previous_block = self.chain[i-1]if current_block.previous_hash != previous_block.hash:return Falseif not self.is_valid_proof(current_block, self.difficulty):return Falsereturn True
Creating the Web Application:
The final step is to create a web application that will
expose our blockchain and allow us to interact with it.
And use Flask to create a simple web server that will
handle GET and POST requests from Postman request. We
will define the following routes for our web
application:
-
/mine_block: this route will mine a new
block by calling the proof_of_work method on the
previous block and passing the proof and
previous_hash to the create_block method. And return
a JSON response with the details of the new block
and a success message.
-
/get_chain: this route will return a JSON
response with the length of our chain and the list
of blocks in our chain.
- /is_valid: this route will check if our chain is valid by calling the is_chain_valid method. And return a JSON response with a boolean value and a message.
Our web application should look like this:
from flask import Flask, jsonify
app = Flask(__name__)blockchain = Blockchain()@app.route('/mine_block', methods=['GET'])def mine_block():previous_block = blockchain.get_previous_block()proof = blockchain.proof_of_work(previous_block)previous_hash = previous_block.hashnew_block = blockchain.create_block(proof, previous_hash)response = {'message': 'Congratulations, you just mined a block!','index': new_block.index,'timestamp': new_block.timestamp,'data': new_block.data,'previous_hash': new_block.previous_hash,'nonce': new_block.nonce,'hash': new_block.hash}return jsonify(response), 200@app.route('/get_chain', methods=['GET'])def get_chain():response = {'length': len(blockchain.chain), 'chain': [str(block) for block in blockchain.chain]}return jsonify(response), 200@app.route('/is_valid', methods=['GET'])def is_valid():valid = blockchain.is_chain_valid()response = {'valid': valid,'message': 'The blockchain is valid' if valid else 'The blockchain is not valid'}return jsonify(response), 200if __name__ == '__main__':app.run(debug=True)
How to Interact with a Blockchain using Python?
We will use Postman to make requests to our web
application. And use the following steps:
1. Run the web application:
Run our web application by executing the python
blockchain.py command in our terminal. We should see a
message like this:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)* Restarting with stat* Debugger is active!* Debugger PIN: 123-456-789
2. Mine a block:
We will mine a new block by sending a GET request to the
/mine_block route using Postman. We should see a JSON
response like this:
{"message": "Congratulations, you just mined a block!","index": 1, "timestamp": "2022-01-28 12:34:56.789000","data": "Some data","previous_hash": "0","nonce": 123456,"hash": "0000abcdef1234567890"}
3. Get the chain:
We will get the chain by sending a GET request to the
/get_chain route using Postman. We should see a JSON
response like this:
{"length": 1,"chain": ["Block 1\nTimestamp: 2022-01-28 12:34:56.789000\nData: Some data\nPrevious Hash: 0\nNonce: 123456\nHash: 0000abcdef1234567890"]}
4. Check the validity:
We can check the validity of our chain by sending a GET
request to the /is_valid route using Postman. We should
see a JSON response like this:
{"valid": true,"message": "The blockchain is valid"}
We can repeat these steps to mine more blocks and
interact with our blockchain.
Conclusion:
In this blog post, we learned about the blockchain
development with some tools and frameworks. And have
learned:
- How to create a smart contract using Solidity.
- How to test and deploy a Blockchain Application.
- How to interact with a deployed smart contract.
- How to create and interact with a blockchain using Python.
We hope you enjoyed this tutorial and learned something
new. If you have any questions or feedback.
Please feel free to leave a comment below. Thank you for
reading! 😊