0% found this document useful (0 votes)
11 views36 pages

Lab Manual

Uploaded by

Neha.Kale K
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views36 pages

Lab Manual

Uploaded by

Neha.Kale K
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 36

Date of Performance:

Date of Submission:
EXPERIMENT NO: 1

AIM : To implement Merkle Hash Tree.


Theory:
Merkle tree also known as hash tree is a data structure used for data verification and
synchronization. A Merkle tree is a hash-based data structure that is a generalization of the
hash list. It is a tree structure in which each leaf node is a hash of a block of data, and each non-leaf
node is a hash of its children. Typically, Merkle trees have a branching factor of 2, meaning that
each node has up to 2 children.

Benefits and Protocol:


In various distributed and peer-to-peer systems, data verification is very important. This is because
the same data exists in multiple locations. So, if a piece of data is changed in one location, it's
important that data is changed everywhere. Data verification is used to make sure data is the same
everywhere.
However, it is time-consuming and computationally expensive to check the entirety of each file
whenever a system wants to verify data. So, this is why Merkle trees are used. Basically, we want
to limit the amount of data being sent over a network (like the Internet) as much apossible. So,
instead of sending an entire file over the network, we just send a hash of the file to see if it
matches. The protocol goes like this:

1) Computer A sends a hash of the file to computer B.


\

2) Computer B checks that hash against the root of the Merkle tree.
3) If there is no difference, we're done! Otherwise, go to step 4.
4) If there is a difference in a single hash, computer B will request the roots of the two
subtrees of that hash.
5) Computer A creates the necessary hashes and sends them back to computer B.
6) Repeat steps 4 and 5 until you've found the data blocks(s) that are inconsistent. It's
possible to find more than one data block that is wrong because there might be more
than one error in the data.
Complexity:
Merkle trees have very little overhead when compared with hash lists. Binary Merkle trees, like
the one pictured above, operate similarly to binary search trees in that their depth is bounded by
their branching factor, 2. Included below is worst-case analysis for a Merkle tree with a branching
factor of k.
\

Code:
from typing import List
import typing
import hashlib
class Node:
def init (self, left, right, value: str)-> None:
self.left: Node = left
self.right: Node =
right self.value = value
@staticmethod
def hash(val: str)-> str:
return hashlib.sha256(val.encode('utf-8')).hexdigest()
@staticmethod
def doubleHash(val: str)-> str:
return Node.hash(Node.hash(val))
class MerkleTree:
def init (self, values: List[str])-> None:
self. buildTree(values)
def buildTree(self, values: List[str])-> None:
leaves: List[Node] = [Node(None, None, Node.doubleHash(e)) for
e in values]
if len(leaves) % 2 == 1:
leaves.append(leaves[-1:][0]) # duplicate last elem if odd number
of elements
self.root: Node = self. buildTreeRec(leaves)
def buildTreeRec(self, nodes: List[Node])-> Node:

half: int = len(nodes) // 2


if len(nodes) == 2:
return Node(nodes[0], nodes[1], Node.doubleHash(nodes[0].value
+ nodes[1].value))
left: Node = self. buildTreeRec(nodes[:half])
right: Node = self. buildTreeRec(nodes[half:])
\

value: str = Node.doubleHash(left.value + right.value)


return Node(left, right, value)
def printTree(self)-> None:
self. printTreeRec(self.root)
def printTreeRec(self, node)-> None:
if node != None:
print(node.value)
self. printTreeRec(node.left)
self. printTreeRec(node.right)
def getRootHash(self)-> str:
return self.root.value
def test()-> None:
elems = ["Hello", "mister", "Merkle" , "tree" ]
mtree = MerkleTree(elems)
print(mtree.getRootHash())
test()

Output:

Conclusion: From the experiment we got to know how merkle trees work and why they are an
integral part of so many technologies and also how you can use merkle trees to solve issues that
require data verification, consistency verification, and data synchronization.
\

Date of Performance:

Date of Submission:

Experiment No. 2

Aim: Creating and deploying Smart Contract using Solidity and Remix IDE.

Theory:

● Smart contract is a computer program or a transaction protocol which is intended to


automatically execute, control or document legally relevant events and actions according to
the terms of a contract or an agreement.
● Remix IDE (Integrated Development Environment) is a web application that can be used to
write, debug, and deploy Ethereum Smart Contracts.
● Solidity is a contract-oriented, high-level language for implementing smart contracts.

Step 1: Go to https://remix.ethereum.org/. Under the contracts folder, you will find some default
contracts already given to us by Remix.

Step 2: right-click on the contracts and select New File. Name our file as Voting and type the
following code. Save file with .sol extension.
\

pragma solidity ^0.6.6;

contract Voting{

struct Candidate{
\

uint id; string name;

uint voteCount;

mapping (uint => Candidate) public candidates;

uint public candidatecount;

mapping (address => bool) public citizen;

constructor() public{

addCandidate("Godlin");

addCandidate("Hilda");

function addCandidate(string memory _name) private{

candidatecount++;

candidates[candidatecount] = Candidate(candidatecount, _name, 0);

function vote(uint _candidateid) public{

require(!citizen[msg.sender]);

citizen[msg.sender] = true;

candidates[_candidateid].voteCount ++;

}
In above program with line pragma solidity ^0.6.6; the version of Solidity is specified as 0.6.6, as
it is a stable version. Data type Candidate is defined with struct keyword. Mapping in Solidity acts
like a hash table or dictionary in any other language. These are used to store the data in the form of
key-value pairs, a key can be any of the built-in data types. In the Candidates mapping, we have
the key as type uint. As said already, this will be the ID to identify the candidate. In the Citizen
mapping, we are using the key as the address and boolean as the value. So initially, the boolean
value for a citizen will be false and once they have cast their vote, it will change to true. By this,
\

we can make sure that each citizen can cast their vote only once.
\

This function is used to handle voting. The require(!citizen[msg.sender]) is used to check if the citizen is
already voted. Cause in case they have already voted their boolean value will be True, so the condition
will fail not allowing the citizen to vote again. If this is their first vote, we change the boolean value of
the citizen as True and increment the voteCount of the particular candidate that the city chose to vote
with the help of the candidateid

constructor() public{
addCandidate("Godlin");
addCandidate("Hilda");
}

As most of you are already aware, a constructor is called at the beginning of a program. In our
case, the constructor is called when we deploy our contract. So when we are deploying, we are
adding two candidates named — Godlin and Hilda.

Step 3 : Click on the solidity compiler present on the left. You can select Auto-compile so our
contract automatically compiles when we do some changes.
\

Step 4: After compiling our contract, now is the time to deploy our simple contract. For that click on
run and deploy transactions on the left. Then click on Deploy. After your contract is successfully
deployed, you will able to see your contract under the deployed contract.

Step 5: Now we can access the information of the Candidate using the id. You will see the
candidate mapping will require uint256 as input. If you give the input as 1, you will be to see the
details of our first candidate. In our case, the first candidate is Godlin.
\

Step 6: You will notice that the first account will have less ether when compared to the rest, that is
because by default Remix will the first account to deploy our contract. If we want to deploy a
contract we have to pay some ether as gas. Now select the second account and let’s cast our vote.
Go to our deployed contract present in the bottom and vote for your candidate.
\

Source code: Palindrome Program

Output:
\

Observations and Findings: From this we came to know that solidity is a object-oriented high
level programming language for creating a smart contract that runs on the Ethereum blockchain.
We have learned about the smart contact and its creation using solidity programming.

Conclusion: We have successfully created and deployed the smart contract.

Date of Performance:

Date of Submission:

R1 R2 R3 R4 R5 Total
Signature
(3 Marks) (3 Marks) (3 Marks) (3 Mark) (3 marks) (15 Marks)

Experiment No. 3
\

Theory:

● Consider a smart contract for basic banking operations. This contract includes all of the
functionalities and capabilities that Solidity presents. Also, it demonstrates about how to
send ETH between any account and the contract developed (from an account to a contract
or from a contract to an account) and how to restrict the people who can use the relevant
function of the smart contract.

● Create a client object to keep the client’s information, which will join the contract by using
the struct element. It keeps the client’s ID, address, and balance in the contract. Then we
create an array in the client_account type to keep the information of all of our clients.

● Assign an ID to each client whenever they join the contract, so we define an int counter and
set it to 0 in the constructor of the contract.

● Define an address variable for the manager and a mapping to keep the last interest date of
each client. Since we want to restrict the time required to send interest again to any
account, it’ll be used to check whether enough time has elapsed.

● In a smart contract, in order to restrict the people that can call the relevant method or to
allow the execution of the method only specific circumstances. In these kinds of
circumstances, the modifier checks the condition you’ve implemented, and it determines
whether the relevant method should be executed.

● Before implementing all of the methods we need to organize the smart contract, we have to
implement two modifiers. Both methods will check the people who call the relevant
method and which of the modifiers is used. One of them determines whether the sender is
the manager, and the other one determines whether the sender is a client.

● The fallback function is essential to making the contract receive ether from any address.
The receive keyword is new in Solidity 0.6.x, and it’s used as a fallback function to receive
ether. Since we’ll receive ether from the clients as a deposit, we need to implement the
fallback function.
\

● The setManager method will be used to set the manager address to variables we’ve defined.
The managerAddress is consumed as a parameter and cast as payable to provide sending
ether. The joinAsClient method will be used to make sure the client joins the contract.
Whenever a client joins the contact, their interest date will be set, and the client information
will be added to the client array.
● The deposit method will be used to send ETH from the client account to the contract. We
want this method to be callable only by clients who’ve joined the contract, so the
onlyClient modifier is used for this restriction. The transfer methods belong to the contract,
and it’s dedicated to sending an indicated amount of ETH between addresses. The payable
keyword makes receipt of the ETH transfer possible, so the amount of ETH indicated in the
msg.value will be transferred to the contract address.
● The withdraw method will be used to send ETH from the contract to the client account. It
sends the unit of ETH indicated in the amount parameter, from the contract to the client
who sent the transaction. We want this method to be callable only by clients who’ve joined
the contract either, so the onlyClient modifier is used for this restriction. The address of the
sender is held in the msg.sender variable.
● The sendInterest method will be used to send ETH as interest from the contract to all
clients. We want this method to be callable only by the manager, so the onlyManager
modifier is used for this restriction. Here, the last date when the relevant client takes the
interest will be checked for all of the clients, and the interest will be sent if the specific time
period has elapsed. Finally, the new interest date is reset for the relevant client into the
interestDate array if the new interest is sent. The getContractBalance method will be used
to get the balance of the contract we deployed.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.6;

contract BankContract {

struct client_account{

int client_id;

address client_address;

uint client_balance_in_ether;

client_account[] clients;

int clientCounter;
\

address payable manager;

mapping(address => uint) public interestDate;

modifier onlyManager() {

require(msg.sender == manager, "Only manager can call this!");

_;

modifier onlyClients() {

bool isclient = false;

for(uint i=0;i<clients.length;i++){

if(clients[i].client_address == msg.sender){

isclient = true;

break;

require(isclient, "Only clients can call this!");

_;

constructor() public{

clientCounter = 0;

receive() external payable { }

function setManager(address managerAddress) public returns(string memory){

manager = payable(managerAddress);
\

return "";

function joinAsClient() public payable returns(string memory){

interestDate[msg.sender] = now;

clients.push(client_account(clientCounter++, msg.sender, address(msg.sender).balance));

return "";

function deposit() public payable onlyClients{

payable(address(this)).transfer(msg.value);

function withdraw(uint amount) public payable onlyClients{

msg.sender.transfer(amount * 1 ether);

function sendInterest() public payable onlyManager{

for(uint i=0;i<clients.length;i++){

address initialAddress = clients[i].client_address;

uint lastInterestDate = interestDate[initialAddress];

if(now < lastInterestDate + 10 seconds){

revert("It's just been less than 10 seconds!");

payable(initialAddress).transfer(1 ether);

interestDate[initialAddress] = now;

}
\

function getContractBalance() public view returns(uint){

return address(this).balance;

Step 1: Create BankContract.sol and Compile the Smart Contract


\
\

Step 3: Run the Transactions

Now, we’re ready to call the functions that compound the smart contract developed. When we
expand the relevant contract in the Deployed Contract subsection, the methods developed appear.

The setManager method

We’re starting to simulate a small process by calling these methods. First, we’re supposed to set a
manager. Therefore, we type an address that we select from the account combo and click the
yellow setManager button. The following output happens in the terminal. The decoded output
shows the message that returned from the method, which is an empty string message — as we
expected.

The joinAsClient method

We’ll continue to join as a client for three clients that we determined from the account combo and
call the joinAsClient method for each one. At this time — and this is different from the previous
one. we should call the method while selecting related accounts because we take the msg.sender
value from here. Select three addresses one by one and press joinAsClient button. We get
following output.
\

The deposit method

Now, we’ll send 10 ETH from the clients’ accounts to the contract by using the deposit method. In
the deposit method, we take the amount declared in the msg.value from the sender that’s
represented in the msg.sender variable. Therefore, we set 10 ETH and call the deposit method by
clicking the red deposit button for each client account, like we did before for the joinAsClient
method. After these operations, the following messages show in the terminal, which means those
three accounts sent 10 ETH from their account to the contract address. Also, the final state of the
\

The getContractBalance method

Now, we call the getContractBalance method to check whether the 30 ETH that was sent from the
clients exist in the contract account. Therefore, we click the blue getContractBalance button, and it
returns an amount that corresponds to 30 ETH in Wei.
\

The sendInterest method

After checking that the contract isn’t empty anymore, we can send interest to our clients by calling
the sendInterest method. We select the account that we’ve set as manager account before and click
the red sendInterest button. The message in the image above appears after calling the method in the
terminal. This message means that 1 ETH was sent to each client’s account successfully. We can
see the balance of each client increased from 89 to 90 ETH after this operation.

We implemented a restriction that checks whether 10 seconds have elapsed since the sendInterest
method was called. To check this control, we call the same method one more time in 10 seconds.
The transaction went as expected, and the "It’s just been less than 10 seconds!" message appeared
in the terminal, as in the image below.

The withdraw method

Now, we call the last method we’ve developed to withdraw an amount from the contract to the
client’s account. In the withdraw method, we transfer the amount declared in the msg.value from
the account to the sender that’s represented in the msg.sender variable. At this point, there’s a
problem realized, which is that the people who haven’t joined the contract as a client can call this
method too. We use the onlyClient modifier to avoid this problem. When we select an account
belonging to anyone who hasn’t joined the contract as a client and then call the withdraw method
\

through the red withdraw button, the "Only clients can call this!" is displayed:

After calling the method, we see the ETH amount increased as much as we were expecting.

The balance of the sender


\

Source code:

pragma solidity ^0.6.6;

contract BankContract {

struct client_account{

int client_id;

address client_address;

uint client_balance_in_ether;

client_account[] clients;

int clientCounter;

address payable manager;

mapping(address => uint) public interestDate;

modifier onlyManager() {

require(msg.sender == manager, "Only manager can call this!");

_;

modifier onlyClients() {

bool isclient = false;

for(uint i=0;i<clients.length;i++){

if(clients[i].client_address == msg.sender){
\

isclient = true;

break;

require(isclient, "Only clients can call this!");

_;

constructor() public{

clientCounter = 0;

receive() external payable { }

function setManager(address managerAddress) public returns(string memory){

manager = payable(managerAddress);

return "";

function joinAsClient() public payable returns(string memory){

interestDate[msg.sender] = now;

clients.push(client_account(clientCounter++, msg.sender, address(msg.sender).balance));

return "";

function deposit() public payable onlyClients{

payable(address(this)).transfer(msg.value);

}
\

function withdraw(uint amount) public payable onlyClients{

msg.sender.transfer(amount * 1 ether);

function sendInterest() public payable onlyManager{

for(uint i=0;i<clients.length;i++){

address initialAddress = clients[i].client_address;

uint lastInterestDate = interestDate[initialAddress];

if(now < lastInterestDate + 10 seconds){

revert("It's just been less than 10 seconds!");

payable(initialAddress).transfer(1 ether);

interestDate[initialAddress] = now;

function getContractBalance() public view returns(uint){

return address(this).balance;

}
\

Output:

Initial Value
\

Deposit Value:

Withdraw Amount:
\

Observations and Findings: We have successfully understood what solidity is and how smart
contracts work. We have implemented how transactions happen in a contract, along with
depositing and withdrawing ethers from our account.
Conclusion: In this experiment, smart contract is successfully deployed on the Remix IDE. We
tested all of the functionalities it presents by performing the transactions.

R1 R2 R3 R4 R5 Total
Signature
(3 Marks) (3 Marks) (3 Marks) (3 Mark) (3 marks) (15 Marks)
\
\
\
\
\
\

You might also like