Lab Manual
Lab Manual
Date of Submission:
EXPERIMENT NO: 1
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:
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:
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.
\
contract Voting{
struct Candidate{
\
uint voteCount;
constructor() public{
addCandidate("Godlin");
addCandidate("Hilda");
candidatecount++;
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.
\
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.
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;
\
modifier onlyManager() {
_;
modifier onlyClients() {
for(uint i=0;i<clients.length;i++){
if(clients[i].client_address == msg.sender){
isclient = true;
break;
_;
constructor() public{
clientCounter = 0;
manager = payable(managerAddress);
\
return "";
interestDate[msg.sender] = now;
return "";
payable(address(this)).transfer(msg.value);
msg.sender.transfer(amount * 1 ether);
for(uint i=0;i<clients.length;i++){
payable(initialAddress).transfer(1 ether);
interestDate[initialAddress] = now;
}
\
return address(this).balance;
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.
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.
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.
\
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
\
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.
\
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.
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.
Source code:
contract BankContract {
struct client_account{
int client_id;
address client_address;
uint client_balance_in_ether;
client_account[] clients;
int clientCounter;
modifier onlyManager() {
_;
modifier onlyClients() {
for(uint i=0;i<clients.length;i++){
if(clients[i].client_address == msg.sender){
\
isclient = true;
break;
_;
constructor() public{
clientCounter = 0;
manager = payable(managerAddress);
return "";
interestDate[msg.sender] = now;
return "";
payable(address(this)).transfer(msg.value);
}
\
msg.sender.transfer(amount * 1 ether);
for(uint i=0;i<clients.length;i++){
payable(initialAddress).transfer(1 ether);
interestDate[initialAddress] = now;
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)
\
\
\
\
\
\