Ethereum
- Jay Dave
1
Blockchain Technology (BITS F452)
1
Outline
Basics of Ethereum
Transaction in Ethereum
Smart Contract
Block in Ethereum
Proof of Work and Proof of Stake
Definition of Ethereum
Simple Definition:
Ethereum is a type of blockchain that allows people to build decentralized
applications (dApps) and create smart contracts, which are self-executing
agreements with the terms written directly into code. Unlike Bitcoin, which is
mostly used for digital currency, Ethereum is more like a global computer network
that can run all kinds of programs without needing a central authority.
Technical Definition:
Ethereum is an open-source, decentralized blockchain platform featuring smart
contract functionality. It utilizes a decentralized virtual machine, the Ethereum
Virtual Machine (EVM), to execute scripts using an international network of public
nodes. Ethereum uses its native cryptocurrency, Ether (ETH), to pay for transaction
fees (gas) and computational services. The blockchain operates on a Proof of Stake
(PoS) consensus mechanism as of the Ethereum 2.0 upgrade, providing scalability,
security, and energy efficiency improvements over its previous Proof of Work (PoW)
model.
3
Compared to Bitcoin
Ethereum shares many common elements with other open blockchains:
a peer-to-peer network connecting participants, a Byzantine fault–tolerant
consensus algorithm for synchronization of state updates (a proof-of-work
blockchain), the use of cryptographic primitives such as digital signatures and
hashes, and a digital currency (ether).
Ethereum’s purpose is not primarily to be a digital currency payment network.
While the digital currency ether is both integral to and necessary for the
operation of Ethereum, ether is intended as a utility currency to pay for use of
the Ethereum platform as the world computer.
Unlike Bitcoin, which has a very limited scripting language, Ethereum is designed
to be a general-purpose programmable blockchain that runs a virtual machine capable
of executing code of arbitrary and unbounded complexity.
Where Bitcoin’s Script language is, intentionally, constrained to simple true/false
evaluation of spending conditions, Ethereum’s language is Turing complete, meaning
that Ethereum can function as a general-purpose computer.
4
The Birth of Ethereum
Ethereum was conceived at a time when people recognized the power of the Bitcoin
model, and were trying to move beyond cryptocurrency applications.
But developers faced a conundrum: they either needed to build on top of Bitcoin or
start a new blockchain.
The limited set of transaction types, data types, and sizes of data storage seemed
to limit the sorts of applications that could run directly on Bitcoin;
anything else needed additional off-chain layers, and that immediately negated many
of the advantages of using a public blockchain.
For projects that needed more freedom and flexibility while staying on-chain, a new
blockchain was the only option.
5
Ethereum’s Timeline
6
https://inevitableeth.com/home/ethereum/history
Ethereum’s Components
P2P network: Ethereum runs on the Ethereum main network, which is addressable on
TCP port 30303, and runs a protocol called ÐΞVp2p.
Consensus rules: Ethereum’s consensus rules are defined in the reference
specification, the Yellow Paper.
Transactions: Ethereum transactions are network messages that include (among other
things) a sender, recipient, value, and data payload.
State machine: Ethereum state transitions are processed by the Ethereum Virtual
Machine (EVM), a stack-based virtual machine that executes bytecode (machine-
language instructions). EVM programs, called “smart contracts,” are written in
high-level languages (e.g., Solidity) and compiled to bytecode for execution on the
EVM.
Data structures: Ethereum’s state is stored locally on each node as a database
(usually Google’s LevelDB), which contains the transactions and system state in a
serialized hashed data structure called a Merkle Patricia Tree.
Consensus algorithm: Ethereum uses Bitcoin’s consensus model, Nakamoto Consensus,
which uses sequential single-signature blocks, weighted in importance by PoW to
determine the longest chain and therefore the current state. However, there are
plans to move to a PoS weighted voting system, codenamed Casper, in the near
future.
Clients: Ethereum has several interoperable implementations of the client software,
the most prominent of which are Go-Ethereum (Geth) and Parity.
7
Ethereum is Turing Complete
What is Turing Complete?
A system that can solve any problem that a computer can, by using loops,
conditions, and storing data.
How is Ethereum Turing Complete?
Ethereum is Turing complete because its Ethereum Virtual Machine (EVM) can run any
kind of program.
You can write complex smart contracts that include loops, conditions (if-else), and
other logical operations.
This means that, like a normal computer, Ethereum can handle any kind of
computational task, making it very flexible for developers to create decentralized
applications (dApps) and smart contracts.
8
Implications of Turing Completeness
Turing proved that you cannot predict whether a program will terminate by
simulating it on a computer.
In simple terms, we cannot predict the path of a program without running it.
Turing-complete systems can run in “infinite loops,” a term used (in
oversimplification) to describe a program that does not terminate.
In Ethereum, this poses a challenge: every participating node (client) must
validate every transaction, running any smart contracts it calls.
But as Turing proved, Ethereum can’t predict if a smart contract will terminate, or
how long it will run, without actually running it (possibly running forever).
By accident or on purpose, it results in DoS attack.
Resource-hogging, memory-bloating, CPU-overheating
To answer this challenge, Ethereum introduces a metering mechanism called gas.
Gas is the mechanism Ethereum uses to allow Turing-complete computation while
limiting the resources that any program can consume.
9
Implications of Turing Completeness
As the EVM executes a smart contract, it carefully accounts for every instruction
(computation, data access, etc.).
Each instruction has a predetermined cost in units of gas.
When a transaction triggers the execution of a smart contract, it must include an
amount of gas that sets the upper limit of what can be consumed running the smart
contract.
The EVM will terminate execution if the amount of gas consumed by computation
exceeds the gas available in the transaction.
10
Currency Units
ether (ETH)
small unit = gwei
smaller unit = wei
1 ETH = 10^18 wei
1 ETH = 10^9 gwei
1 gwei = 10^9 wei
11
Transaction
https://www.blockchain.com/explorer/transactions/eth/
0x044ae830ba9c7afd8e71e4cd5604a3f3f29a5ca34fbb7aa3ebb9d3b1bb18dd92
https://www.blockchain.com/explorer/blocks/eth/21128905
hash: "0x044ae830ba9c7afd8e71e4cd5604a3f3f29a5ca34fbb7aa3ebb9d3b1bb18dd92"
Unique identifier (ID) of this transaction
Computed by hashing the transaction's contents (nonce, gas price, gas limit, to,
from, value, data, etc.) using the Keccak-256 hashing algorithm.
blockHash: "0x20b77a9214f23f3a9ec0882c868d11b3799a4cd26312734c5b59746fff4eecf6"
The hash of the block in which this transaction was included.
This is generated by hashing the block header using Keccak-256. It ensures the
transaction is tied to a specific block in the blockchain.
12
Transaction
"blockNumber": "21128905",
The number of the block that contains this transaction.
Assigned sequentially by the Ethereum blockchain. Each block has a unique number
that increases by one as new blocks are added to the chain.
"to": "0xd29da236dd4aac627346e1bba06a619e8c22d7c5"
The recipient address of the transaction.
Defined by the sender. If this is a transfer to a regular address, it represents a
simple Ether transfer or token transfer. If it’s a smart contract address, the
transaction is likely interacting with a contract.
"from": "0xdaee26abc7f8cdb58954d76509bf4ca54234e57f"
The address of the sender who initiated the transaction.
This is the address derived from the public key of the sender, who signed the
transaction. The address is also stored in the blockchain state.
13
Transaction
"value": "0"
The amount of Ether (in Wei) being transferred from the sender to the recipient.
Defined by the sender. In this case, it’s zero, which often indicates that this
transaction is not transferring ETH but interacting with a smart contract.
"nonce": "18"
A unique integer for each transaction from a specific account, representing the
number of transactions previously sent from this account.
The sender's Ethereum account keeps track of the nonce. It starts at 0 and
increments by 1 for each transaction. Here, the sender has sent 18 transactions
prior to this one.
"gasPrice": "24024667092"
The price (in Wei) per unit of gas the sender is willing to pay.
Defined by the sender based on current network conditions. Higher gas prices
typically lead to faster transaction inclusion by miners or validators.
14
Transaction
"gasLimit": "52283",
The maximum number of gas units the sender allows this transaction to consume.
Defined by the sender. It caps the amount of gas the transaction can use. If the
transaction uses less gas than this limit, the remaining gas is refunded to the
sender. If it needs more than this limit, it fails.
"gasUsed": "46599"
The actual amount of gas units consumed by the transaction upon execution.
Computed by the Ethereum Virtual Machine (EVM) based on the operations performed.
For this transaction, the EVM used 46,599 gas units.
"data":
"095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7fffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffff"
Optional input data associated with the transaction, usually when interacting with
a smart contract.
This data field is created by encoding the function call and arguments when
interacting with a smart contract. In this example, it appears to be calling a
specific function (095ea7b3 is the function selector) with parameters provided in
the following bytes.
15
Transaction
"transactionIndex": "78",
The position of this transaction within the block.
Determined by the order in which transactions were processed and included in the
block by miners.
"success": true,
Indicates whether the transaction was successfully executed.
Computed based on the EVM execution. If all required gas and conditions are met,
the transaction is marked successful. If the transaction fails due to out-of-gas or
invalid operations, it is marked as failed.
"state": "CONFIRMED",
The current state of the transaction.
Computed based on the number of confirmations. If enough blocks have confirmed this
transaction, it’s considered confirmed and irreversible.
16
Transaction
"timestamp": "1730899691",
The time (in Unix epoch format) when the block containing this transaction was
mined.
Taken from the block header’s timestamp field, representing the time the block was
mined.
"internalTransactions": []
A list of internal transactions triggered by the main transaction, usually in smart
contract executions.
Created when a transaction to a smart contract triggers additional contract calls
or Ether transfers within the EVM. Since this field is empty, this transaction did
not trigger any internal transactions.
17
Nonce
One of the most important and least understood components of a transaction.
nonce: A scalar value equal to the number of transactions sent from this address
or, in the case of accounts with associated code, the number of contract-creations
made by this account. (Ref: Yellow paper)
an attribute of the originating address
However, the nonce is not stored explicitly as part of an account’s state on the
blockchain.
Instead, it is calculated dynamically, by counting the number of confirmed txns
that have originated from an address.
18
Nonce
Scenario 1:
Imagine you wish to make two txns.
You have an important payment to make of 6 ether, and also another payment of 8
ether.
You sign and broadcast the 6-ether txn first, because it is the more important one,
and then you sign and broadcast the second, 8-ether txn.
Sadly, you have overlooked the fact that your account contains only 10 ether, so
the network can’t accept both txns: one of them will fail.
Because you sent the more important 6-ether one first, you understandably expect
that 8-ether one to be rejected.
However, in a decentralized system like Ethereum, nodes may receive the txns in
either order.
Without the nonce, it would be random as to which one gets accepted and which
rejected.
However, with the nonce included, the first txn you sent will have a nonce of,
let’s say, 3, while the 8-ether txn has the next nonce value (i.e., 4).
So, that txn will be ignored until the txns with nonces from 0 to 3 have been
processed, even if it is received first.
19
Nonce
Scenario 2:
Now imagine you have an account with 100 ether.
You find someone online who will accept payment in ether for a software that you
really want to buy.
You send them 2 ether and they send you the software.
To make that 2-ether payment, you signed a txn sending 2 ether from your account to
their account, and then broadcast it to the Ethereum network to be verified and
included on the blockchain.
Now, without a nonce value in the txn, a second txn sending 2 ether to the same
address a second time will look exactly the same as the first txn.
20
Nonce
Scenario 2:
This means that anyone who sees your txn on the Ethereum network (which means
everyone, including the recipient or your enemies) can “replay” the txn again and
again and again until all your ether is gone simply by copying and pasting your
original txn and resending it to the network.
However, with the nonce value included in the txn data, every single txn is unique,
even when sending the same amount of ether to the same recipient address multiple
times.
Thus, by having the incrementing nonce as part of the txn, it is simply not
possible for anyone to “duplicate” a payment you have made.
In summary, it is important to note that the use of the nonce is actually vital for
an account-based protocol, in contrast to the “Unspent txn Output” (UTXO) mechanism
of the Bitcoin protocol.
21
Keeping Track of Nonces
In practical terms, the nonce is an up-to-date count of the number of confirmed
(i.e., on-chain) transactions that have originated from an account.
Your wallet will keep track of nonces for each address it manages.
Let’s say you are writing your own wallet software. How do you track nonces?
When you create a new transaction, you assign the next nonce in the sequence.
But until it is confirmed, it will not count.
22
Keeping Track of Nonces
a. Ethereum Nodes (Clients)
Ethereum nodes (like Geth, OpenEthereum, or Nethermind) maintain an up-to-date
state of all accounts, including each account's nonce.
When an account initiates a transaction, the node queries the current nonce from
the state.
{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": ["0xYourAccountAddress", "pending"],
"id": 1
}
23
Keeping Track of Nonces
b. DApps and Web3 Libraries
In DApps, developers typically use libraries like Web3.js (for JavaScript),
Ethers.js, or Web3.py (for Python) to interact with Ethereum nodes.
These libraries track nonces by querying the Ethereum node. For example:
Web3.js: web3.eth.getTransactionCount(address, 'pending')
Ethers.js: provider.getTransactionCount(address, 'pending')
24
Keeping Track of Nonces
c. Manual Tracking for Custom Implementations
In high-throughput applications or custom implementations (e.g., exchanges,
wallets, and bots), relying solely on the node’s response can sometimes lead to
nonce conflicts, especially if there are multiple concurrent transactions.
To handle this, applications often maintain their own in-memory or database-based
nonce tracking:
Database Tracking: Nonces for each account can be stored in a database (SQL or
NoSQL). When a transaction is created, the application retrieves the current nonce,
increments it, and updates the stored value. This method is useful when tracking
nonces for multiple accounts, such as in exchanges or high-frequency trading
applications.
In-Memory Tracking: For simpler applications with fewer accounts, nonces can be
tracked in memory (e.g., using a hashmap). The application updates the nonce each
time it creates a new transaction.
25
Keeping Track of Nonces
d. Handling Pending Transactions and Failed Transactions
Pending Transactions: Since the transaction pool can include multiple unconfirmed
transactions, it’s essential to consider these pending transactions to avoid
duplicate nonce use. Always use the "pending" option when querying nonces.
Failed Transactions: If a transaction fails (e.g., due to insufficient gas), its
nonce is still considered "used" on the blockchain. Future transactions from that
account must use an incremented nonce.
26
Handling Gaps and Duplication
Ethereum network processes txns sequentially, based on the nonce.
It means that if you transmit a txn with nonce 0 and then transmit a txn with nonce
2, the second txn will not be included in any blocks. It will be stored in the
mempool, while Ethereum network waits for the missing nonce to appear.
All nodes will assume that the missing nonce has simply been delayed and that the
txn with nonce 2 was received out of sequence.
If you then transmit a transaction with the missing nonce 1, both transactions
(nonces 1 and 2) will be processed and included (if valid, of course).
Once you fill the gap, the network can mine the out-of-sequence transaction that it
held in the mempool.
It means that if you create several txns in sequence and one of them does not get
officially included in any blocks, all the subsequent txns will be “stuck,” waiting
for missing nonce.
It is not possible to “recall” a txn!
27
Handling Gaps and Duplication
Nonce Duplications
Definition: It happens when two or more txns are sent with the same nonce. This can
occur due to concurrent txn submissions or incorrect nonce tracking.
Impact: Only one txn with a specific nonce will be accepted and confirmed by the
network. The others will be rejected or replace the original txn if they have a
higher gas price.
28
Handling Gaps and Duplication
Preventing Nonce Gaps and Duplications
a. Sequential Transaction Submission
Strategy: Submit transactions one after another, ensuring that each transaction is
confirmed before sending the next.
Pros: Simplifies nonce management and avoids gaps.
Cons: Slower transaction throughput, not suitable for high-frequency applications.
b. Concurrent Submission with Proper Tracking
Strategy: Allow multiple transactions to be submitted concurrently while
maintaining an accurate nonce tracking system.
Implementation Steps:
1. Fetch the Latest Nonce: Always query the latest nonce from the blockchain using
"pending" to include unconfirmed transactions.
2. Assign Unique Nonces: Ensure each concurrent transaction is assigned a unique
nonce based on the latest known nonce.
3. Update Local Tracking: Immediately update the local nonce tracker upon assigning
a nonce to prevent reuse.
29
Handling Gaps and Duplication
Preventing Nonce Gaps and Duplications
c. Implementing Mutexes or Locks
Strategy: Use synchronization mechanisms to prevent multiple processes from
assigning the same nonce simultaneously.
d. Using Nonce Management Libraries
Strategy: Leverage existing libraries designed for efficient nonce management.
Examples: NonceManager (Ethers.js), Web3.js Helpers.
30
Handling Gaps and Duplication
Preventing Nonce Gaps and Duplications
e. Maintaining a Local Nonce Tracker
Strategy: Keep a local record of the last used nonce and increment it for each new
transaction.
let currentNonce = await provider.getTransactionCount(address, "pending");
function getNextNonce() {
return currentNonce++;
}
Database Tracking: Essential for high-throughput or distributed systems. Store
Nonce in Database, Atomic Increment.
BEGIN;
SELECT nonce FROM accounts WHERE address = '0xYourAddress' FOR UPDATE;
UPDATE accounts SET nonce = nonce + 1 WHERE address = '0xYourAddress';
COMMIT;
31
Handling Gaps and Duplication
Resolving Nonce Gaps and Duplications
a. Detecting Nonce Gaps using Transaction Status Monitoring and Blockchain
Explorers.
b. Replace the transaction: By sending another transaction with the same nonce but
a higher gas price. This is useful if txn is stuck due to a low gas price. OR
b. Cancel the transaction: Send a new transaction with the same nonce but with zero
value and a higher gas price to effectively cancel it.
32
How to handle concurrency through multiple wallets?
1. Centralized Nonce Manager: Each wallet or application requests a nonce from this
nonce manager before sending a transaction.
2. Transaction Queueing System: Implement a queueing system where transactions are
buffered and processed sequentially.
33
Gas, Gas price, Gas limit, and Gas used
Gas: is the unit used to measure the amount of computational work required to
perform an operation on the Ethereum network.
This could be executing a transaction, deploying a contract, or running a function
within a smart contract.
Purpose: To prevent overloading the network by ensuring users pay for computational
resources, which helps avoid infinite loops or excessively complex computations.
Each operation (like adding numbers, storing data, etc.) has a predefined gas cost.
E.g. a simple addition might cost 3 gas, whereas more complex storage operations
can cost thousands of gas.
Gas Price: is the amount of Ether (ETH) a user is willing to pay per unit of gas
for a transaction. It’s typically measured in gwei.
Purpose: To incentivizes miners. Higher gas prices make a transaction more
attractive to miners, helping it get confirmed faster.
If the gas price is 20 gwei and a transaction requires 50,000 gas, the total cost
would be:
20 gwei × 50,000 = 1,000,000 gwei = 0.001ETH
Gas prices vary based on network congestion. During high traffic, gas prices rise
as users compete for limited block space.
34
Gas, Gas price, Gas limit, and Gas used
Gas Limit: is the maximum amount of gas a user is willing to allocate for a
particular transaction. It sets an upper boundary on how much the transaction will
cost, preventing unexpectedly high charges.
Setting an appropriate gas limit ensures the transaction has enough gas to
complete. If the gas limit is too low, the transaction will run out of gas mid-way,
fail, and consume all the gas without achieving its goal.
For a simple ETH transfer, a gas limit of 21,000 is typical. However, more complex
transactions, like executing a smart contract function, may need significantly
more.
GasUsed: GasUsed is the actual amount of gas consumed by a transaction once it’s
executed on the network.
While gas limit is the maximum a user is willing to pay, gasUsed is the actual
amount needed to execute the transaction.
If the gasUsed is lower than the gas limit, the user only pays for the gas that was
actually used, and the unused portion is refunded.
If you set a gas limit of 100,000 but the transaction only needed 50,000 gas, then
50,000 gas is refunded.
However, if your transaction runs out of gas (e.g., needs 150,000 but you set
100,000), it fails, and all 100,000 gas is consumed without completing the
operation.
35
Ethereum Addresses
Unique identifiers that are derived from public keys or contracts using the Keccak-
256 one-way hash function.
Externally Owned Accounts (EOA) Address Computation
Steps:
1. Generate a Private Key (256-bit (32-byte))
2. Compute the Public Key (512-bit (64-byte))
secp256k1: y2 = x3 + 7,
P = k ⋅ G, where (x, y) derived. |x| = |y| = 256 bits
3. Hash the Public Key using Keccak-256(P)
4. Extract the Address: last 20 bytes (40 hex characters) of this 32-byte Keccak-
256 hash.
Ethereum addresses are hexadecimal numbers, identifiers derived from the last 20
bytes of the Keccak-256 hash of the public key.
36
Contract Address
Next slide…
37
Contract Address
A contract address is an Ethereum address similar to a regular wallet address, but
it specifically identifies a smart contract.
Address Derivation
Contract Address=Keccak-256(RLP(Deployer Address∣∣Nonce))
- Recursive-Length Prefix (RLP) serialization protocol is an encoding scheme to
represent and store structured data.
- Nonce: The deployer’s transaction count at the time of deployment.
38
Digital Signatures
Uses Elliptic Curve Digital Signature Algorithm (ECDSA)
Purposes:
1) The signature proves that the owner of the private key, who is by implication
the owner of an Ethereum account, has authorized the spending of ether, or
execution of a contract.
2) It guarantees non-repudiation: the proof of authorization is undeniable.
3) The signature proves that the transaction data has not been and cannot be
modified by anyone after the transaction has been signed.
39
Digital Signatures
Elliptic Curve Digital Signature Algorithm (ECDSA)
Key Generation
Select EC.
Select a point A which generates a cyclic
group of prime order q.
Choose a random integer d.
Compute B = dA.
kpub = (p, a, b, q, A, B)
kpr = (d)
Signature Generation
Select kE and compute R = (kE)A.
Select r = xR.
Compute s ≡ ((h(x) + d*r)kE-1) mod q
40
Signature Verification:
1. Compute auxiliary value w ≡ s-1 mod q
2. Compute auxiliary value u1 ≡ w*h(x) mod q
3. Compute auxiliary value u2 ≡ w*r mod q
4. Compute P = u1A + u2B
5. xP ≡ r mod q??
Digital Signatures
Elliptic Curve Digital Signature Algorithm (ECDSA)
Correctness Proof:
s ≡ (h(x) + d.r)kE-1 mod q
kE = (s-1 Hash(x) + ds-1r) mod q
kE = u1 + du2 mod q
(kE)A = (u1 + du2 )A
(kE)A = (u1)A + (du2)A
(kE)A = (u1)A + (u2)dA
(kE)A = (u1)A + (u2)B
41
Digital Signatures
Elliptic Curve Digital Signature Algorithm (ECDSA)
42
Bob
EC: p = 17, a = 2, b =2
A = (5, 1) and q = 19.
d = 7
B = dA = (0,6)
(p, a, b, q, A, B) = (17, 2, 2, 19, (5,1), (0,6))
h(x) = 26
kE = 10
R =kE*A = 10*(5,1) = (7,11)
r = xR = 7
s = (26 + 7*7)*2 mod 19 = 17 mod 19
x,(7, 17)
Verify:
1. w = 17-1 mod 19 = 9
2. u1 = 9*26 mod 19 = 6 mod 19
3. u2 = 9*7 mod 19 = 6 mod 19
4. P = 6(5,1) + 6 (0,6) = (7,11)
5. xP = 7 = r mod 19
Alice
42
Transaction Value and Data
Transaction Value
The Value field in a transaction specifies the amount of Ether (ETH) being sent
from the sender’s account to the recipient’s account.
Simple ETH Transfer: If a transaction is just a transfer of ETH, then the value
field is non-zero, and the data field is empty.
Contract Interaction: When interacting with a smart contract, the value field can
still specify an ETH amount to send along with the contract call. For example, if
the contract function expects payment, the value field could contain the necessary
amount.
43
Transaction Value and Data
1. Transmitting Value to EOAs
Transaction Structure: The transaction includes the to field (address of the
recipient EOA) and the value field (amount of Ether in wei).
Execution: There’s no code execution required. The transaction simply moves Ether
from the sender’s account to the recipient’s account.
Gas Requirement: Since no computation is needed, only a minimal amount of gas
(typically 21,000 units) is required to cover basic processing and record the
transfer on the blockchain.
E.g.
https://www.blockchain.com/explorer/transactions/eth/0x0ad1b61b7f6ed71d5c86e38e0119
1ac959a228ca4ed6ac6fec8bc86f0b34c8d4
44
Transaction Value and Data
2. Transmitting Value to Smart Contracts
In upcoming slide…
45
Transaction Value and Data
Transaction Data
The Data field in a transaction serves a different purpose: it specifies
information that can be used by a smart contract.
This is particularly useful when the transaction is calling a function in a smart
contract or passing specific parameters to that function.
Purpose of the Data Field
Calling Smart Contracts: When a transaction interacts with a smart contract, the
data field encodes the function that’s being called and any parameters passed to
that function.
Arbitrary Data Storage: Users can also send arbitrary data (messages, metadata,
etc.) in the data field. However, doing so incurs gas costs, and storing
unnecessary data on-chain is generally discouraged.
46
Transaction Value and Data
1. Transmitting Data to EOAs
In most cases, when you send Ether to an EOA, the transaction contains only the
value (amount of Ether) and no data payload.
When your transaction contains data, it is most likely addressed to a contract
address. That doesn’t mean you cannot send a data payload to an EOA—that is
completely valid in the Ethereum protocol.
However, in that case, the interpretation of the data is up to the wallet you use
to access the EOA.
It is ignored by the Ethereum protocol.
47
Transaction Value and Data
1. Transmitting Data to EOAs: Why Would You Send a Data Payload to an EOA?
1) Metadata for Off-Chain Processing:
The data payload could contain metadata that the recipient EOA (or the user
controlling it) needs for some off-chain process. For example, the transaction
might include a reference ID or a message.
A backend service or a monitoring tool can listen for transactions sent to an EOA,
extract the data payload, and act on it.
2) Signaling or Notifications:
It can be used to signal information to the owner of the EOA. For instance, in
decentralized applications, a contract might send a transaction to an EOA with a
message embedded in the data field as a form of notification.
3) Interoperability with Custom Wallet Software:
Some advanced Ethereum wallets might be programmed to watch for incoming
transactions with specific data payloads.
The wallet software could then trigger specific actions based on the data received.
48
Transaction Value and Data
1. Transmitting Data to EOAs: How EOAs Handle Data Payloads
EOAs do not process or interpret the data payload because they do not have
executable code (unlike smart contracts).
The data simply becomes part of the transaction’s record on the blockchain.
The recipient (human user) can manually review the data or use custom software to
extract and interpret the data if needed.
https://drive.google.com/file/d/1CmE7RFLWEbDdg5fr0ySjkheKmSjsAVIl/view?usp=sharing
49
Transaction Value and Data
2. Transmitting Data to Smart Contracts
Next slide…
50
Transaction Value and Data
Transmitting Value to Smart Contracts
Transmitting value to a smart contract involves sending Ether along with a
transaction to the contract's address.
This is commonly done to: 1) Pay for a service or functionality (e.g., buying
insurance), 2) Fund the contract (e.g., for payouts in insurance).
In the context of the insurance contract, the purchasePolicy function demonstrates
how value is transmitted.
E.g. purchasePolicy()'s msg.value as premium.
Transmitting Data to Smart Contracts
Transmitting data involves passing parameters or instructions to a smart contract
via function calls.
This is essential for: 1) Executing specific functionality (e.g., triggering a
payout). 2) Customizing the behavior of the contract (e.g., setting thresholds).
E.g. triggerPayout(actualDelay)
51
Smart Contracts
52
Smart Contract Account
Two different types of accounts in Ethereum: externally owned accounts (EOAs) and
contract accounts.
EOAs are controlled by users, often via software such as a wallet application that
is external to the Ethereum platform.
Contract accounts are controlled by program code (also commonly referred to as
“smart contracts”) that is executed by the Ethereum Virtual Machine.
EOAs are controlled by transactions created and cryptographically signed with a
private key in the “real world” external to and independent of the protocol,
whereas contract accounts do not have private keys and so “control themselves” in
the predetermined way prescribed by their smart contract code.
Both types of accounts are identified by an Ethereum address.
53
What Is a Smart Contract?
In the 1990s, cryptographer Nick Szabo defined it as “a set of promises, specified
in digital form, including protocols within which the parties perform on the other
promises.”
In the context of Ethereum, the term is actually a bit of a misnomer
Ethereum smart contracts are neither smart nor legal contracts, but the term has
stuck.
“Smart contracts” refers to immutable computer programs that run deterministically
in the context of an Ethereum Virtual Machine as part of the Ethereum network
protocol—i.e., on the decentralized Ethereum world computer.
54
What Is a Smart Contract?
Computer programs: Smart contracts are simply computer programs. The word
“contract” has no legal meaning in this context.
Immutable: Once deployed, the code of a smart contract cannot change. Unlike with
traditional software, the only way to modify a smart contract is to deploy a new
instance.
Deterministic: The outcome of the execution of a smart contract is the same for
everyone who runs it, given the context of the transaction that initiated its
execution and the state of the Ethereum blockchain at the moment of execution.
EVM context: Smart contracts operate with a very limited execution context. They
can access their own state, the context of the transaction that called them, and
some information about the most recent blocks.
Decentralized world computer: The EVM runs as a local instance on every Ethereum
node, but because all instances of the EVM operate on the same initial state and
produce the same final state, the system as a whole operates as a single “world
computer.”
55
Life Cycle of a Smart Contract
1. Development and Coding: Typically written in a high-level language, such as
Solidity.
2. Compilation: Written code is compiled into bytecode so that it can be understood
by EVM.
3. Deployment: Once compiled, they are deployed on the Ethereum platform using a
special contract creation txn, which is identified as such by being sent to the
special contract creation addr, namely 0x0.
Each contract is identified by an Ethereum addr, which is derived from the contract
creation txn as a function of the originating account and nonce.
Ethereum addr of a contract can be used in a txn as the recipient, sending funds to
the contract or calling one of the contract’s functions.
56
Life Cycle of a Smart Contract
4. Execution: Contracts only run if they are called by a txn initiated from an EOA.
A contract can call another contract that can call another contract, and so on, but
the first contract in such a chain of execution will always have been called by a
txn from an EOA.
Users pay gas fees for executing functions, which are required for processing and
storing data.
Contracts never run “on their own” or “in the background.”
Contracts effectively lie dormant until a txn triggers execution, either directly
or indirectly as part of a chain of contract calls.
Smart contracts are not executed “in parallel” in any sense—Ethereum world computer
can be considered to be a single-threaded machine.
57
Life Cycle of a Smart Contract
5. Termination: Contract’s code cannot be changed.
However, a contract can be “deleted,” removing the code and its internal state
(storage) from its address,
To delete a contract, you execute an EVM opcode called SELFDESTRUCT (previously
called SUICIDE).
That operation costs “negative gas,” a gas refund, thereby incentivizing the
release of network client resources from the deletion of stored state.
Deleting a contract in this way does not remove the transaction history (past) of
the contract, since the blockchain itself is immutable.
SELFDESTRUCT capability will only be available if the contract author programmed
the smart contract to have that functionality.
If the contract’s code does not have a SELFDESTRUCT opcode, or it is inaccessible,
the smart contract cannot be deleted.
58
Ethereum High-Level Languages
LLL: A functional (declarative) programming language, with Lisp-like syntax. It was
the first high-level language for Ethereum smart contracts but is rarely used
today.
Serpent: A procedural (imperative) programming language with a syntax similar to
Python. Can also be used to write functional (declarative) code, though it is not
entirely free of side effects.
Solidity: A procedural (imperative) programming language with a syntax similar to
Java Script, C++, or Java. The most popular and frequently used language for
Ethereum smart contracts.
Vyper: A more recently developed language, similar to Serpent and again with
Pythonlike syntax. Intended to get closer to a pure-functional Python-like language
than Serpent, but not to replace Serpent.
Bamboo: A newly developed language, influenced by Erlang, with explicit state
transitions and without iterative flows (loops). Intended to reduce side effects
and increase auditability. Very new and yet to be widely adopted.
59
Download and Install Solidity
sudo apt update
sudo apt upgrade
sudo apt install software-properties-common
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt update
sudo apt upgrade
sudo apt install solc
Verify the installation: solc –version
https://www.youtube.com/watch?v=kdvVwGrV7ec
60
Basic Structure of a Solidity Program
1. Pragma Directive: The pragma directive specifies the version of the Solidity
compiler to be used. This helps ensure compatibility with future versions of the
compiler.
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
1) Using a Specific Version: pragma solidity 0.8.17;, 2) Using a Version Range:
pragma solidity >=0.8.0 <0.9.0;
3) Using a Version or any patchwork with backward compatibility: pragma solidity
^0.8.0;
4) Using any version in the 0.8.x series: pragma solidity >=0.8.*;
2. Contract Definition: A contract in Solidity is similar to a class in object-
oriented languages like Python or Java. It's a core building block that contains
variables, functions, events, and modifiers.
contract MyFirstContract {
// Code for the contract goes here
}
3. State Variables: State variables are variables whose values are stored on the
blockchain. They define the state of the contract and persist between function
calls.
contract MyFirstContract {
uint public number; // State variable
address public owner; // State variable to store the owner's address
}
61
Basic Structure of a Solidity Program
3. State Variables: State variables are variables whose values are stored on the
blockchain. They define the state of the contract and persist between function
calls.
Where are State Variables Stored?
State variables are stored in the Ethereum blockchain's storage, which is the most
persistent and expensive form of storage in Solidity. This storage is designed to
hold data permanently across all Ethereum nodes.
In contrast:
Local variables: Exist only during function execution and are stored in memory or
stack.
Function parameters: Passed as inputs to functions and exist temporarily in memory.
Syntax for Declaring State Variables: State variables are declared inside the
contract but outside any function.
<Data Type> <Visibility> <var name>
62
Data Types
Boolean (bool): Boolean value, true or false, with logical operators ! (not), &&
(and), || (or), == (equal), and != (not equal).
E.g. bool public isCompleted = false;
Integer (int, uint): Signed (int) and unsigned (uint) integers, declared in
increments of 8 bits from int8 to uint256. Without a size suffix, 256-bit
quantities are used, to match the word size of the EVM.
E.g.
uint public age = 25;
int public temperature = -10;
Address: A 20-byte Ethereum address. The address object has many helpful member
functions, the main ones being balance (returns the account balance) and transfer
(transfers ether to the account).
E.g. address public owner = msg.sender;
Arrays: An array of any type, either fixed or dynamic: uint32[][5] is a fixed-size
array of five dynamic arrays of unsigned integers.
E.g.
uint[] public numbers; // Dynamic array
uint[5] public fixedArray; // Fixed-size array
Mapping: Hash lookup tables for key ⇒ value pairs: mapping(KEY_TYPE ⇒ VALUE_TYPE)
NAME.
E.g. mapping(address => uint) public balances;
63
Data Types
String: Used to store text data.
E.g. string public greeting = "Hello, Solidity!";
Bytes: Used for storing raw byte data. Commonly used types are bytes1 to bytes32
and bytes.
E.g. bytes32 public dataHash = keccak256(abi.encodePacked("data"));
Visibility Modifiers for State Variables
public: Allows anyone (external users, contracts, or functions) to access the
variable. Solidity automatically creates a getter function for public state
variables.
private: Restricts access to the variable to within the contract where it is
defined. Even derived contracts cannot access private state variables.
internal: Allows access within the contract and derived contracts. This is the
default visibility if none is specified.
external: This specifier is not used with state variables; it's only applicable to
functions.
64
Data Types
Fixed-point numbers in Solidity were intended to represent fractional numbers
(i.e., numbers with a decimal point) using fixed precision. They are declared using
the types:
fixedMxN: Signed fixed-point number.
ufixedMxN: Unsigned fixed-point number.
M: Specifies the size in bits (increments of 8 up to 256).
N: Specifies the number of decimals after the point (up to 18).
E.g. ufixed32x2 value; // Unsigned fixed-point with 32 bits, 2 decimal places
However, fixed-point types (fixed, ufixed) are not currently fully supported in
Solidity. They are reserved keywords, but you cannot use them in your contracts at
this time.
Alternative Approach
uint256 public scaledValue = 12345; // Represents 123.45 with 2 decimals
uint256 public decimals = 2;
function getRealValue() public view returns (uint256) {
return scaledValue / (10 ** decimals);
}
65
Data Types
Byte Array (Fixed): Fixed-size byte arrays are used to store raw binary data with a
predefined size.
bytes1 to bytes32: Represents arrays of bytes of sizes from 1 to 32.
E.g. bytes32 public data = "Hello, Solidity!";
Byte Array (Dynamic): Dynamic byte arrays allow for storing variable-length
sequences of bytes. They are declared using:
bytes: A dynamic array of raw bytes.
string: A dynamic array specifically for storing text.
E.g.
bytes public byteArray;
string public text;
Struct: A struct is a user-defined data type that allows you to group multiple
variables into a single type. Structs are useful for organizing related data and
creating complex data structures.
struct Person {
string name;
uint age;
address wallet;
}
66
Data Types
Enum: An enum (enumeration) is a user-defined type that allows you to define a set
of named values. Enums are great for representing states or options with a
restricted set of possible values.
contract EnumExample {
enum Status { Pending, Shipped, Delivered, Cancelled }
Status public currentStatus;
function setStatus(Status _status) public {
currentStatus = _status;
}
function getStatus() public view returns (Status) {
return currentStatus;
}
function cancelOrder() public {
currentStatus = Status.Cancelled;
}
}
67
Data Types
Predefined Global Variables
68
Basic Structure of a Solidity Program
msg Object: The msg object contains information about the current transaction and
the message sent to the contract.
msg.sender: Returns the address of the entity that called the function.
address public owner;
constructor() {
owner = msg.sender; // Sets the owner to the address that deployed the contract
}
msg.value: Returns the amount of Ether sent with the transaction.
function deposit() public payable {
require(msg.value > 0, "Must send some Ether");
}
69
Basic Structure of a Solidity Program
msg Object: The msg object contains information about the current transaction and
the message sent to the contract.
msg.data: Returns the complete calldata (input data) sent with the transaction.
function logData() public pure returns (bytes memory) {
return msg.data;
}
msg.sig: Returns the first 4 bytes of msg.data, which represent the function
signature.
function getFunctionSelector() public pure returns (bytes4) {
return msg.sig;
}
70
Basic Structure of a Solidity Program
block Object: The block object provides information about the current block.
block.number: The current block number.
function getCurrentBlock() public view returns (uint) {
return block.number;
}
block.timestamp: The timestamp of the current block.
function isRecent(uint _timestamp) public view returns (bool) {
return (block.timestamp - _timestamp) < 1 days;
}
71
Basic Structure of a Solidity Program
block Object: The block object provides information about the current block.
block.difficulty: The difficulty level of the current block (used in mining).
function getDifficulty() public view returns (uint) {
return block.difficulty;
}
block.coinbase: The address of the miner who mined the current block.
function getMinerAddress() public view returns (address) {
return block.coinbase;
}
72
Basic Structure of a Solidity Program
tx Object
tx.origin: The original sender of the transaction (not recommended for access
control due to security risks).
function getOrigin() public view returns (address) {
return tx.origin;
}
73
Basic Structure of a Solidity Program
4. Modifiers (Optional)
Modifiers are reusable pieces of code used to modify the behavior of functions.
They are typically used for access control.
modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_; // Placeholder for the function body
}
The onlyOwner modifier ensures that only the contract owner can execute specific
functions.
The underscore (_) indicates where the modified function's code will be executed.
74
Basic Structure of a Solidity Program
5. Functions: Functions define the behavior of the contract. They can be used to
modify the state, interact with other contracts, or perform calculations.
Basic Syntax of a Function:
function functionName(parameters) visibility modifier returns (type) {
// Function logic goes here
}
E.g.
pragma solidity ^0.8.0;
contract MyContract {
function greet() public pure returns (string memory) {
return "Hello, Solidity!";
}
}
75
75
Basic Structure of a Solidity Program
5. Functions:
Types of Functions:
Function Visibility Specifiers
1. public: Can be called externally (by anyone) and internally (within the
contract).
function setNumber(uint _num) public {
number = _num;
}
2. private: Can only be called internally within the contract. Not accessible by
derived contracts or external users.
function _calculate(uint a, uint b) private pure returns (uint) {
return a + b;
}
76
Basic Structure of a Solidity Program
5. Functions:
Types of Functions:
Function Visibility Specifiers
3. internal: Can be called internally and by derived contracts, but not externally.
function _helper() internal view returns (string memory) {
return "Internal function";
}
4. external:
Can only be called externally, not from within the contract.
Typically used for functions intended to be called by other contracts or users.
function externalFunction() external pure returns (string memory) {
return "Called externally";
}
77
Basic Structure of a Solidity Program
5. Functions:
Types of Functions:
B) Function State Mutability: State mutability defines whether a function modifies
or reads the blockchain state.
1. view: Indicates that the function reads the blockchain state but does not modify
it.
function getBalance() public view returns (uint) {
return address(this).balance;
}
2. pure: Indicates that the function does not read or modify the blockchain state.
function add(uint a, uint b) public pure returns (uint) {
return a + b;
}
3. payable: Indicates that the function can receive Ether. Functions with this
specifier can accept payments.
function deposit() public payable {
// Now the contract can receive Ether
}
4. Non-Specified (default): If no mutability keyword is specified, the function can
read and modify the state.
78
Basic Structure of a Solidity Program
5. Functions:
Types of Functions:
Modifiers: Modifiers are reusable blocks of code used to change the behavior of
functions, often for access control. The underscore (_) represents where the
function's original code will execute.
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
function setOwner(address _owner) public onlyOwner {
owner = _owner;
}
79
Basic Structure of a Solidity Program
5. Functions:
80
Basic Structure of a Solidity Program
a) Ether Transfer Functions
address.send(): Sends Ether and returns true if successful, false otherwise (does
not revert on failure).
function sendEther(address payable recipient) public payable {
bool sent = recipient.send(msg.value);
require(sent, "Failed to send Ether");
}
address.transfer(): Sends Ether and reverts if it fails.
function transferEther(address payable recipient) public payable {
recipient.transfer(msg.value);
}
address.call(): Low-level call used for interacting with other contracts. It
returns a boolean and data.
function callFunction(address target) public returns (bool) {
(bool success, ) = target.call{value: msg.value}("");
return success;
}
81
Basic Structure of a Solidity Program
b) Error Handling Functions
assert(): Used for checking internal errors. It reverts the transaction and
consumes all gas if the condition is false.
function safeDivide(uint a, uint b) public pure returns (uint) {
assert(b != 0);
return a / b;
}
require(): Used for input validation and conditions. It reverts the transaction if
the condition is not met but refunds unused gas.
function withdraw(uint amount) public {
require(balance[msg.sender] >= amount, "Insufficient balance");
balance[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
revert(): Reverts the transaction with an optional error message.
function customRevert() public pure {
revert("Custom error message");
}
82
Basic Structure of a Solidity Program
c) Cryptographic Functions
keccak256(): Computes the Keccak-256 hash of the input.
function hashData(string memory data) public pure returns (bytes32) {
return keccak256(abi.encodePacked(data));
}
abi.encode() and abi.decode(): Used to encode and decode data.
function encodeData(uint a, string memory b) public pure returns (bytes memory) {
return abi.encode(a, b);
}
function decodeData(bytes memory data) public pure returns (uint, string memory) {
return abi.decode(data, (uint, string));
}
83
Basic Structure of a Solidity Program
Contract Self-Destruction
function closeContract() public {
require(msg.sender == owner, "Not the owner");
selfdestruct(payable(owner));
}
84
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
An event in Solidity is a way for a smart contract to emit logs to the blockchain.
Once an event is emitted, it is stored in the transaction log and becomes
accessible to external applications that subscribe to these events.
Events are stored on the blockchain, but they are not directly accessible by
contracts (i.e., contracts cannot read past events).
They are useful for logging data, monitoring contract activity, and triggering
asynchronous actions in off-chain applications.
Gas efficient: Writing to the event log is cheaper than updating state variables
because event data is stored in a separate data structure.
Think of an event as a notification system. When something significant happens in
your contract (e.g., a token transfer, a user registration, etc.), your contract
emits an event that external applications can listen for. This is similar to how a
web application might use notifications to inform users of updates.
85
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
Declaring an Event
event EventName(dataType indexed variable1, dataType variable2);
Emitting an Event
emit EventName(value1, value2);
86
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract EventExample {
// Declare an event
event Transfer(address indexed from, address indexed to, uint256 value);
// Function to trigger the event
function transfer(address to, uint256 amount) public {
// Emit the event
emit Transfer(msg.sender, to, amount);
}
}
87
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
Understanding Indexed Parameters
When you declare an event, you can use the indexed keyword for up to three
parameters.
Indexed parameters allow the event logs to be filtered by those fields, making it
more efficient for off-chain applications to search for specific events.
event ProductSold(uint indexed productId, address indexed buyer, uint amount);
Indexed parameters are stored in the Bloom filter of the log, which makes searching
for specific events more efficient.
Limitations of Indexed Parameters: You can have a maximum of three indexed
parameters per event.
88
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
Practical Use Cases for Events
a) Logging Transactions: Events are commonly used to log transactions, such as
token transfers or changes in contract state.
contract Token {
mapping(address => uint256) public balances;
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
emit Transfer(msg.sender, to, amount);
}
}
89
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
Practical Use Cases for Events
b) Monitoring State Changes: Events can be used to monitor specific state changes
in your contract, such as user registration or role assignment.
event UserRegistered(address indexed user, string name);
function registerUser(string memory name) public {
emit UserRegistered(msg.sender, name);
}
90
Basic Structure of a Solidity Program
6. Events: Events are used to log data on the blockchain, making it accessible to
external applications (like front-end interfaces).
Practical Use Cases for Events
c) Handling Errors and Debugging: Events can help with debugging by logging
specific information, especially in complex contracts.
event ErrorLog(string reason);
function divide(uint a, uint b) public returns (uint) {
if (b == 0) {
emit ErrorLog("Division by zero");
return 0;
}
return a / b;
}
91
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
A constructor is a special function that is executed only once when a smart
contract is deployed on the blockchain.
The purpose of a constructor is to initialize the contract’s state variables and
perform other setup tasks, such as setting the contract owner or assigning initial
values.
Executed only once: The constructor is executed only during the deployment of the
contract.
Used for initialization: It is typically used to set initial values for state
variables or perform other setup tasks.
No return values: Constructors do not have a return type.
Optional: If no constructor is defined, a default constructor is provided by
Solidity.
Basic Constructor Syntax
constructor(parameters) {
// Initialization code
}
92
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyContract {
address public owner;
// Constructor
constructor() {
// Set the owner to the address that deploys the contract
owner = msg.sender;
}
}
msg.sender: The address that deployed the contract, which is assigned to the owner
variable.
93
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
Parameterized Constructors: Constructors can accept parameters, allowing you to
pass initial values when deploying the contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Token {
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
94
// Parameterized constructor
constructor(string memory _name, string memory _symbol, uint8 _decimals,
uint256 _totalSupply) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _totalSupply;
}
}
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
Access Control Using Constructors: A common use case for constructors is to set up
access control by assigning the deploying address as the contract owner.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AccessControl {
address public owner;
// Constructor sets the contract owner
constructor() {
owner = msg.sender;
}
95
modifier onlyOwner() {
require(msg.sender == owner, "Not the contract owner");
_;
}
function changeOwner(address newOwner) public onlyOwner {
owner = newOwner;
}
}
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
Inheritance and Constructors: In Solidity, constructors can be used with
inheritance to initialize the parent contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Parent contract
contract BaseContract {
string public baseName;
constructor(string memory _baseName) {
baseName = _baseName;
}
}
96
// Child contract inherits from BaseContract
contract DerivedContract is BaseContract {
string public derivedName;
constructor(string memory _baseName, string memory _derivedName)
BaseContract(_baseName) // Call the parent constructor
{
derivedName = _derivedName;
}
}
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
BaseContract has a parameterized constructor.
The DerivedContract inherits BaseContract and uses the BaseContract(_baseName)
syntax to call the parent constructor.
97
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
Self-Destructing Contracts with Constructors: Sometimes, you might want to create a
self-destructing contract that destroys itself after performing an action.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SelfDestructContract {
address payable public owner;
// Constructor sets the contract owner
constructor() payable {
owner = payable(msg.sender);
}
98
// Self-destruct function
function closeContract() public {
require(msg.sender == owner, "Not the owner");
selfdestruct(owner); // Destroy the contract and send remaining Ether to
owner
}
}
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
Can a contract have more than one constructor?
No, Solidity contracts can have only one constructor.
Can a constructor be called after deployment?
No, the constructor is executed only once during deployment and cannot be called
again.
Can a contract inherit a constructor?
Yes, a derived contract can inherit the parent contract’s constructor and can also
pass arguments to it.
99
Basic Structure of a Solidity Program
7. Constructor (Optional): The constructor is a special function that runs only
once when the contract is deployed. It's commonly used to initialize state
variables.
contract MyFirstContract {
address public owner;
// Constructor to set the owner of the contract
constructor() {
owner = msg.sender; // `msg.sender` is the address that deployed the
contract
}
}
msg.sender: Represents the address of the account interacting with the contract.
The constructor is optional but useful for initializing contract state.
Example: https://drive.google.com/open?
id=1CmNeqHsQEBry8IoV0dJncuL8kOla3som&usp=drive_fs
100
Some real smart contracts' definitions
1. Token Contracts (ERC-20, ERC-721): These smart contracts define how tokens
(cryptocurrencies, digital assets, or NFTs) are created, issued, and transferred on
a blockchain.
To create digital currencies (like stablecoins or project tokens).
To issue and manage Non-Fungible Tokens (NFTs) representing unique assets.
To digitize assets, automate their management, and enable peer-to-peer transactions
without intermediaries.
2. Decentralized Finance (DeFi) Contracts: These are smart contracts that automate
financial services like lending, borrowing, and trading on decentralized platforms.
To allow users to earn interest, borrow funds, or trade assets without needing a
traditional bank.
To democratize access to financial services, reduce costs, and eliminate the need
for intermediaries.
3. Supply Chain Management: Smart contracts are used to track the movement of goods
along the supply chain, ensuring transparency and authenticity.
To improve visibility, reduce fraud, and automate payments upon delivery.
To enhance trust between suppliers, manufacturers, and consumers by providing a
transparent and tamper-proof record of transactions.
101
Some real smart contracts' definitions
4. Insurance Contracts: Smart contracts automate the claims process, reducing
paperwork and delays.
To automatically release payouts when pre-defined conditions (like flight delays or
natural disasters) are met.
To increase efficiency, reduce administrative costs, and provide faster payouts to
customers.
5. Real Estate and Property Transfers: Smart contracts can automate property sales
and ownership transfers by eliminating intermediaries.
To securely transfer property ownership, automate payments, and reduce the need for
costly escrow services.
To streamline the property buying process, reduce costs, and ensure transparency.
6. Decentralized Autonomous Organizations (DAOs): Smart contracts are used to
manage decentralized organizations where decisions are made through voting by token
holders.
To manage a community or organization without central leadership, relying on rules
encoded in smart contracts.
To create transparent and democratic governance structures where no single party
has full control.
102
Some real smart contracts' definitions
7. Gaming and Digital Collectibles: Smart contracts are used to issue unique
digital assets (NFTs) that players can own, trade, or use within games.
To create in-game assets that have real-world value and can be traded across
different games or platforms.
To give players true ownership of digital items and create new revenue streams in
gaming.
8. Crowdfunding and Fundraising: Smart contracts are used to raise funds in a
transparent and automated manner.
To collect contributions from supporters and automatically release funds to project
creators once funding goals are met.
To increase trust in crowdfunding by ensuring funds are only released if project
conditions are satisfied.
103
1) Token Contracts (ERC-20, ERC-721)
Token contracts are one of the most popular and widely used types of smart
contracts on the Ethereum blockchain. They define how tokens (cryptocurrencies,
digital assets, or NFTs) are created, issued, managed, and transferred between
users.
The most common standards for token contracts are ERC-20 for fungible tokens and
ERC-721 for non-fungible tokens (NFTs).
A token contract is a smart contract that defines and manages a specific type of
digital asset on a blockchain. Tokens can represent:
Cryptocurrencies (e.g., USDT, DAI)
Digital collectibles or NFTs (e.g., CryptoKitties, Bored Ape Yacht Club)
Assets like shares, bonds, or real estate in digital form
Utility tokens used in decentralized applications (dApps)
104
1) Token Contracts (ERC-20, ERC-721)
These token contracts adhere to specific standards to ensure interoperability
across the Ethereum network and other compatible blockchains.
ERC-20 Token Standard (Fungible Tokens): The ERC-20 (Ethereum Request for Comment
20) token standard is the most widely used standard for creating fungible tokens on
the Ethereum blockchain. Fungible means that each token is identical and
interchangeable with every other token of the same type, much like how traditional
currencies (like dollars or bitcoins) work.
105
1) Token Contracts (ERC-20, ERC-721)
106
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleERC20Token {
string public name = "MyToken";
string public symbol = "MTK";
uint8 public decimals = 18;
uint256 public totalSupply = 1000000 * (10 ** uint256(decimals));
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
constructor() {
balanceOf[msg.sender] = totalSupply;
}
function transfer(address to, uint256 amount) public returns (bool) {
require(balanceOf[msg.sender] >= amount, "Insufficient balance");
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
return true;
}
function approve(address spender, uint256 amount) public returns (bool) {
allowance[msg.sender][spender] = amount;
return true;
}
function transferFrom(address from, address to, uint256 amount) public returns
(bool) {
require(balanceOf[from] >= amount, "Insufficient balance");
require(allowance[from][msg.sender] >= amount, "Allowance exceeded");
balanceOf[from] -= amount;
balanceOf[to] += amount;
allowance[from][msg.sender] -= amount;
return true;
}
}
https://drive.google.com/file/d/1G47Y1TUKjwvdfGO9E_JDGXH8i7yjBlJF/view?usp=sharing
1) Token Contracts (ERC-20, ERC-721)
ERC-721 Token Standard (Non-Fungible Tokens - NFTs): The ERC-721 standard is used
for creating non-fungible tokens (NFTs). Unlike fungible tokens (ERC-20), NFTs are
unique and not interchangeable. Each ERC-721 token has a unique identifier, making
it ideal for representing digital collectibles, artwork, real estate, or any other
unique assets.
107
1) Token Contracts (ERC-20, ERC-721)
108
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyNFT is ERC721 {
uint256 public tokenCounter;
constructor() ERC721("MyNFT", "MNFT") {
tokenCounter = 0;
}
function mintNFT(address recipient) public returns (uint256) {
tokenCounter += 1;
_safeMint(recipient, tokenCounter);
return tokenCounter;
}
}
https://drive.google.com/open?id=1GBN4ZfnYedeuclv5LAw9BY3ow1z9MnVU&usp=drive_fs
2) Decentralized Finance (DeFi) Contracts
Decentralized Finance (DeFi) refers to the use of blockchain technology and smart
contracts to automate financial services like lending, borrowing, trading, and
more, without relying on traditional financial institutions such as banks or
brokers.
DeFi contracts aim to remove intermediaries, providing a decentralized and
trustless financial system that is open to everyone.
DeFi contracts are smart contracts deployed on blockchains like Ethereum that
enable users to access financial services directly from their wallets. These
contracts are self-executing and automatically enforce the rules of the financial
agreement without the need for a middleman. This allows for peer-to-peer
interactions, reducing fees and increasing transparency.
109
2) Decentralized Finance (DeFi) Contracts
Common Use Cases for DeFi Contracts
a) Lending and Borrowing
Protocols like Aave, Compound, and MakerDAO allow users to lend their assets and
earn interest, or borrow assets by providing collateral.
Users can deposit their cryptocurrency into a lending pool, and others can borrow
against it.
Interest rates are determined algorithmically based on supply and demand.
b) Decentralized Exchanges (DEXs)
Uniswap, SushiSwap, and Balancer are decentralized exchanges that allow users to
swap tokens directly from their wallets.
DEXs use automated market makers (AMMs) instead of traditional order books, relying
on liquidity pools to facilitate trades.
Users can also become liquidity providers to earn fees by supplying tokens to these
pools.
c) Yield Farming and Staking
Yield farming involves locking up cryptocurrency in DeFi platforms to earn rewards
in the form of interest, tokens, or fees.
Staking allows users to lock up their assets in a protocol to support network
security and receive rewards.
d) Stablecoins
Stablecoins like DAI (MakerDAO), USDT (Tether), and USDC (Circle) are DeFi tokens
pegged to the value of fiat currencies like the USD.
They provide a stable store of value, enabling users to avoid the volatility of
cryptocurrencies.
110
2) Decentralized Finance (DeFi) Contracts
Common Use Cases for DeFi Contracts
// Example of a simple lending contract
contract SimpleLending {
mapping(address => uint256) public deposits;
mapping(address => uint256) public loans;
function depositFunds() public payable {
deposits[msg.sender] += msg.value;
}
function borrowFunds(uint256 amount) public {
require(deposits[msg.sender] >= amount, "Insufficient collateral");
loans[msg.sender] += amount;
payable(msg.sender).transfer(amount);
}
function repayLoan() public payable {
loans[msg.sender] -= msg.value;
}
}
111
https://drive.google.com/file/d/1CE4Hqa1RBqDk-dLKuEiJ2wkCA9lWHOFM/view?usp=sharing
2) Decentralized Finance (DeFi) Contracts
Common Use Cases for DeFi Contracts
// A simplified token swap function
function swapTokens(address tokenA, address tokenB, uint256 amount) public {
IERC20(tokenA).transferFrom(msg.sender, address(this), amount);
uint256 swapAmount = getSwapRate(tokenA, tokenB) * amount;
IERC20(tokenB).transfer(msg.sender, swapAmount);
}
112
2) Decentralized Finance (DeFi) Contracts
How DeFi Contracts Work
Users interact with the DeFi protocol by connecting their wallet (e.g., MetaMask).
Users can deposit, borrow, trade, or stake assets directly from their wallets.
The smart contract automatically enforces the terms, such as interest rates, loan
repayments, or token swaps.
Transactions are recorded on the blockchain, providing transparency and
immutability.
113
3) Supply Chain Management
Supply chain management involves coordinating the flow of goods, information, and
finances across multiple stakeholders such as manufacturers, suppliers, logistics
providers, and retailers.
Traditionally, managing supply chains can be complex and inefficient, relying on
manual processes, paperwork, and intermediaries to track the movement of goods.
Smart contracts have emerged as a powerful tool for automating and optimizing
supply chain operations.
By leveraging blockchain technology, smart contracts can bring greater
transparency, efficiency, and trust to supply chain management.
In the context of supply chain management, smart contracts are self-executing
contracts with the terms of the agreement directly written into code.
They run on a blockchain, which ensures that the data is secure, transparent, and
immutable.
Smart contracts can automatically trigger actions, such as payments or
notifications, based on predefined conditions being met.
114
3) Supply Chain Management
How They Work:
Tracking: Smart contracts record every stage of a product's journey, from raw
materials to the finished product reaching the consumer.
Automating Processes: When predefined conditions are met (e.g., a shipment arrives
at a warehouse), the smart contract automatically executes the next step, like
releasing payment to the supplier.
Ensuring Authenticity: Blockchain technology ensures that records are tamper-proof,
helping to combat fraud and counterfeit goods.
115
3) Supply Chain Management
Use cases:
a) Tracking the Movement of Goods
b) Automating Payments and Settlements
c) Ensuring Product Authenticity and Reducing Counterfeits
d) Supply Chain Finance
116
3) Supply Chain Management
117
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SupplyChain {
enum Status {Created, InTransit, Delivered}
struct Shipment {
uint256 id;
address supplier;
address receiver;
Status status;
uint256 timestamp;
}
mapping(uint256 => Shipment) public shipments;
event ShipmentStatusUpdated(uint256 id, Status status, uint256 timestamp);
function createShipment(uint256 id, address receiver) public {
shipments[id] = Shipment(id, msg.sender, receiver, Status.Created,
block.timestamp);
emit ShipmentStatusUpdated(id, Status.Created, block.timestamp);
}
function updateShipmentStatus(uint256 id, Status newStatus) public {
require(shipments[id].supplier == msg.sender, "Only the supplier can
update");
shipments[id].status = newStatus;
shipments[id].timestamp = block.timestamp;
emit ShipmentStatusUpdated(id, newStatus, block.timestamp);
}
function getShipmentStatus(uint256 id) public view returns (Status, uint256) {
return (shipments[id].status, shipments[id].timestamp);
}
}
https://drive.google.com/file/d/1FbGJsiBMzZlzZi1x-_6HXbuuiJJEwNxg/view?usp=sharing
4) Insurance Contracts
Insurance contracts traditionally involve complex paperwork, long processing times,
and reliance on intermediaries, which can lead to delays and higher costs.
Smart contracts on a blockchain offer a solution by automating the insurance claims
process, making it more efficient, transparent, and secure.
Insurance smart contracts are self-executing contracts that automate the insurance
process by handling tasks like policy issuance, premium collection, and claims
processing.
The terms of the insurance policy are written into the smart contract code, which
runs on a blockchain.
How to Implement Insurance Smart Contracts
1) Define the insurance policy terms: Establish the conditions under which claims
are paid.
2) Use oracles: Integrate oracles to fetch real-world data (e.g., flight delays,
weather conditions).
3) Automate payments: Set up the smart contract to automatically release payouts
when conditions are met.
4) Test thoroughly: Ensure the contract is secure and handle edge cases to prevent
exploits.
Real-World Use Cases of Insurance Smart Contracts
a) Flight Delay Insurance, b) Parametric Crop Insurance, c) Health Insurance, d)
Property and Casualty Insurance
118
4) Insurance Contracts
How Do Insurance Smart Contracts Work?
1) Policy Purchase: A customer purchases an insurance policy through a smart
contract.
The smart contract records the policy details on the blockchain and collects the
premium.
2) Data Collection: The smart contract monitors external data sources (like IoT
sensors, weather data, flight status, etc.) to check for the occurrence of insured
events.
For example, in the case of flight delay insurance, the contract can access real-
time flight information.
3) Claims Trigger: If the predefined conditions are met (e.g., a flight delay of
more than 2 hours), the smart contract automatically triggers a payout to the
policyholder.
If no claim is triggered within the policy period, the contract expires.
4) Payout: The smart contract transfers the insurance payout directly to the
policyholder’s wallet, eliminating delays and reducing fraud.
119
4) Insurance Contracts
120
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract FlightInsurance {
address public insurer;
uint256 public premium;
uint256 public payoutAmount;
bool public isClaimed;
string public flightNumber;
uint256 public delayThreshold;
address public policyholder;
event PolicyPurchased(address indexed policyholder, string flightNumber);
event PayoutIssued(address indexed policyholder, uint256 amount);
constructor(string memory _flightNumber, uint256 _delayThreshold, uint256
_payoutAmount) {
insurer = msg.sender;
flightNumber = _flightNumber;
delayThreshold = _delayThreshold;
payoutAmount = _payoutAmount;
}
// Function to purchase insurance
function purchasePolicy() public payable {
require(msg.value == premium, "Incorrect premium amount");
require(policyholder == address(0), "Policy already purchased");
policyholder = msg.sender;
emit PolicyPurchased(msg.sender, flightNumber);
}
// Function to trigger payout if flight is delayed
function triggerPayout(uint256 actualDelay) public {
require(msg.sender == insurer, "Only insurer can trigger payout");
require(!isClaimed, "Payout already claimed");
require(actualDelay >= delayThreshold, "Flight delay not sufficient");
isClaimed = true;
payable(policyholder).transfer(payoutAmount);
emit PayoutIssued(policyholder, payoutAmount);
}
// Function to set premium (only insurer can set)
function setPremium(uint256 _premium) public {
require(msg.sender == insurer, "Only insurer can set premium");
premium = _premium;
}
// Fallback function to receive Ether
receive() external payable {}
}
https://drive.google.com/file/d/1FcLdND0m50RG-JNbeiFpCMA0aDUR88aC/view?usp=sharing
5) Real Estate and Property Transfers
The process of buying, selling, or transferring property ownership is traditionally
complex, involving lawyers, real estate agents, notaries, and other intermediaries.
These processes can be time-consuming, costly, and prone to errors and fraud.
Smart contracts on a blockchain provide a solution by automating property
transactions and ownership transfers, making them faster, more transparent, and
secure.
Real estate smart contracts are self-executing agreements where the terms of the
sale, purchase, or transfer of property ownership are directly written into lines
of code.
These contracts run on a blockchain, ensuring that transactions are immutable,
transparent, and efficient.
121
5) Real Estate and Property Transfers
How Do Real Estate Smart Contracts Work?
a) Property Listing
The property owner lists their property on a blockchain-based platform.
Information such as the property details, price, and terms of sale are stored in a
smart contract.
b) Buyer-Seller Agreement
Once a buyer expresses interest, they agree to the terms set in the smart contract.
The smart contract holds escrow funds (e.g., a deposit) to ensure the buyer's
commitment.
c) Verification and Due Diligence
Smart contracts can integrate with oracles to verify information, such as property
ownership, tax status, and legal compliance.
d) Ownership Transfer
When all conditions are met (e.g., payment received, documents verified), the smart
contract automatically transfers ownership to the buyer.
The new ownership record is updated on the blockchain.
e) Payment Settlement
The smart contract releases the funds to the seller once ownership is successfully
transferred.
This eliminates the need for manual payments and reduces the risk of non-payment.
122
122
5) Real Estate and Property Transfers
Real-World Use Cases of Real Estate Smart Contracts
a) Automated Property Sales
b) Fractional Ownership
c) Rental Agreements
d) Title Management and Deed Transfers
123
5) Real Estate and Property Transfers
124
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract RealEstate {
address public seller;
address public buyer;
uint256 public price;
bool public isSold;
// Events
event PropertyListed(address indexed seller, uint256 price);
event PropertySold(address indexed buyer, uint256 price);
// Constructor to set the initial seller and price
constructor(uint256 _price) {
seller = msg.sender;
price = _price;
isSold = false;
emit PropertyListed(seller, price);
}
// Function to buy the property
function buyProperty() public payable {
require(!isSold, "Property already sold");
require(msg.value == price, "Incorrect payment amount");
buyer = msg.sender;
isSold = true;
emit PropertySold(buyer, price);
payable(seller).transfer(msg.value); // Transfer payment to the seller
}
// Function to get the property details
function getPropertyDetails() public view returns (address, address, uint256,
bool) {
return (seller, buyer, price, isSold);
}
}
https://drive.google.com/file/d/1FuH5lq-_GkNaLeLG8AXMOJrYN2EXyhmg/view?usp=sharing
6) Decentralized Autonomous Organizations (DAOs)
Decentralized Autonomous Organizations (DAOs) are organizations that are run by
smart contracts on a blockchain, where decisions are made by token holders through
a transparent voting process.
Unlike traditional organizations, DAOs operate without centralized control,
allowing members to collectively manage resources and make decisions in a
democratic and decentralized manner.
A DAO is an organization that operates on the principles of decentralization and
automation, where:
Smart contracts automate the rules and processes of the organization.
Decisions are made by voting among token holders, rather than by a centralized
authority.
DAOs are often used for managing community projects, investment funds, or
decentralized protocols.
125
6) Decentralized Autonomous Organizations (DAOs)
2. How Do DAOs Work?
DAOs rely on smart contracts to define the rules of the organization and automate
processes. Here’s a typical workflow:
a) Creation of the DAO
A DAO is created by deploying a smart contract on a blockchain like Ethereum.
The rules of the DAO, such as voting mechanisms and fund allocation, are encoded
into the smart contract.
b) Token Distribution
Members receive governance tokens in exchange for contributions, such as providing
liquidity, funding, or work.
These tokens give members voting rights on proposals and decisions.
c) Proposal and Voting Process
Members can submit proposals (e.g., funding a new project, changing rules, or
allocating resources).
Other members vote on the proposal using their tokens.
If a proposal receives enough votes to meet the quorum (minimum participation
threshold), the decision is implemented automatically.
d) Fund Management
The DAO’s treasury is controlled by the smart contract, ensuring that funds are
only spent based on approved proposals.
This reduces the risk of mismanagement or corruption.
126
6) Decentralized Autonomous Organizations (DAOs)
127
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleDAO {
struct Proposal {
string description;
uint256 votesFor;
uint256 votesAgainst;
bool executed;
mapping(address => bool) voted;
}
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
mapping(address => uint256) public tokenBalance;
address public owner;
event ProposalCreated(uint256 proposalId, string description);
event Voted(uint256 proposalId, address voter, bool support);
event ProposalExecuted(uint256 proposalId);
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
constructor() {
owner = msg.sender;
}
// Function to add tokens to users (for testing)
function mintTokens(address to, uint256 amount) public onlyOwner {
tokenBalance[to] += amount;
}
// Function to create a new proposal
function createProposal(string memory description) public {
proposalCount++;
proposals[proposalCount] = Proposal(description, 0, 0, false);
emit ProposalCreated(proposalCount, description);
}
// Function to vote on a proposal
function vote(uint256 proposalId, bool support) public {
Proposal storage proposal = proposals[proposalId];
require(!proposal.voted[msg.sender], "Already voted");
require(tokenBalance[msg.sender] > 0, "No voting power");
proposal.voted[msg.sender] = true;
if (support) {
proposal.votesFor += tokenBalance[msg.sender];
} else {
proposal.votesAgainst += tokenBalance[msg.sender];
}
emit Voted(proposalId, msg.sender, support);
}
// Function to execute a proposal if it has enough votes
function executeProposal(uint256 proposalId) public {
Proposal storage proposal = proposals[proposalId];
require(!proposal.executed, "Already executed");
require(proposal.votesFor > proposal.votesAgainst, "Not enough votes");
proposal.executed = true;
emit ProposalExecuted(proposalId);
}
}
https://drive.google.com/file/d/1CPu3ex-8BTRSlER9ju5xHEn1YCfCKI7C/view?usp=sharing
7) Gaming and Digital Collectibles
Gaming and digital collectibles are among the most popular use cases for smart
contracts and non-fungible tokens (NFTs) on the blockchain.
Smart contracts enable the creation of unique digital assets that players can own,
trade, and use within games.
This has revolutionized the gaming industry by providing players with true
ownership of in-game items, allowing them to monetize their skills and assets in
ways that were not possible before.
In the context of gaming and digital collectibles, smart contracts are used to
mint, manage, and transfer NFTs that represent unique in-game items, characters, or
collectibles. These assets are stored on a blockchain, giving players true
ownership over their digital assets.
How to Implement Smart Contracts for Gaming and Digital Collectibles
Choose an NFT Standard: Decide whether to use ERC-721 (for unique assets) or ERC-
1155 (for semi-fungible tokens).
Create a Smart Contract: Write a smart contract using Solidity to mint, manage, and
transfer NFTs.
Integrate Metadata: Use metadata standards to include additional information like
images, descriptions, and attributes.
Develop a Front-End: Build a user-friendly interface for players to interact with
the blockchain.
Deploy and Test: Deploy your contract on a blockchain like Ethereum, Polygon, or
Binance Smart Chain and test thoroughly.
128
7) Gaming and Digital Collectibles
How Do Smart Contracts Work in Gaming and Digital Collectibles?
a) Creating Digital Assets as NFTs
Developers use smart contracts to mint NFTs representing unique in-game items, such
as weapons, skins, characters, or collectibles.
These NFTs are stored on a blockchain, making them secure and tamper-proof.
b) Ownership and Transfer of Assets
When a player acquires an in-game item, it is stored in their blockchain wallet as
an NFT.
Players can transfer or sell these items on marketplaces like OpenSea or Rarible.
c) Play-to-Earn Mechanism
Some games offer play-to-earn models, where players can earn NFTs or tokens as
rewards for their in-game achievements.
These rewards can be traded for other assets or converted into real-world money.
d) In-Game Utility
NFTs can have specific utility within games, such as providing special abilities,
unlocking new levels, or customizing characters.
Players can use their NFTs across different games if the games are built on the
same blockchain and support the same NFT standards (e.g., ERC-721 or ERC-1155).
129
7) Gaming and Digital Collectibles
130
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract GameItems is ERC721URIStorage, Ownable {
uint256 public tokenCounter;
event ItemMinted(uint256 tokenId, address owner, string tokenURI);
constructor() ERC721("GameItems", "GMI") {
tokenCounter = 0;
}
// Function to mint a new game item
function mintItem(string memory tokenURI) public returns (uint256) {
tokenCounter++;
uint256 newItemId = tokenCounter;
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
emit ItemMinted(newItemId, msg.sender, tokenURI);
return newItemId;
}
// Function to get the token URI
function getTokenURI(uint256 tokenId) public view returns (string memory) {
return tokenURI(tokenId);
}
}
https://drive.google.com/file/d/1C_1X1coY_XdVevr9GP_ZgvxfgWPZaDE7/view?usp=sharing
8) Crowdfunding and Fundraising
Crowdfunding and fundraising are processes where individuals, organizations, or
startups raise funds from the public to support projects, ventures, or charitable
causes.
Traditionally, these processes require intermediaries like banks, payment
processors, or fundraising platforms (e.g., Kickstarter, GoFundMe), which can lead
to high fees, lack of transparency, and delays.
Smart contracts offer a more efficient, transparent, and automated way to handle
crowdfunding and fundraising on the blockchain.
By using smart contracts, funds can be raised directly from contributors without
intermediaries, and the entire process is governed by predefined rules embedded in
code.
A crowdfunding smart contract is a self-executing contract that runs on a
blockchain and automates the process of raising, managing, and distributing funds.
The terms of the crowdfunding campaign (e.g., funding goal, deadline, and rewards)
are written into the smart contract, ensuring that the process is transparent and
trustless.
How to Implement Crowdfunding Smart Contracts
Define the Campaign Terms: Set the funding goal, deadline, and minimum contribution
amount.
Develop the Smart Contract: Write a smart contract using Solidity that automates
the collection, management, and distribution of funds.
Test the Contract: Thoroughly test the contract to ensure it handles all edge
cases, such as refunds and partial contributions.
Deploy the Contract: Deploy the smart contract to a blockchain like Ethereum,
Polygon, or Binance Smart Chain.
Create a Front-End Interface: Build a user-friendly interface for contributors to
interact with the contract.
131
8) Crowdfunding and Fundraising
How Do Crowdfunding Smart Contracts Work?
a) Campaign Creation
The project creator deploys a smart contract on the blockchain with details like:
Funding goal: The amount needed to fund the project.
Deadline: The date by which the funding goal must be reached.
Minimum contribution: The smallest amount that can be contributed.
Rewards (optional): Incentives for contributors, such as exclusive access or
products.
b) Fund Collection
Contributors send cryptocurrency (e.g., ETH) directly to the smart contract.
The smart contract tracks each contribution and the contributor’s address.
Funds are locked in the smart contract until the campaign ends.
c) Funding Goal Met
If the funding goal is reached before the deadline, the smart contract releases the
funds to the project creator.
If the funding goal is not met, the smart contract automatically refunds the
contributors.
d) Automated Rewards
If rewards are offered, the smart contract can automatically distribute NFTs or
tokens to contributors once the funding goal is achieved.
132
8) Crowdfunding and Fundraising
133
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Crowdfunding {
address public creator;
uint256 public goal;
uint256 public deadline;
uint256 public totalFunds;
mapping(address => uint256) public contributions;
bool public goalReached;
event ContributionReceived(address contributor, uint256 amount);
event FundsWithdrawn(address creator, uint256 amount);
event RefundIssued(address contributor, uint256 amount);
modifier onlyCreator() {
require(msg.sender == creator, "Not the creator");
_;
}
constructor(uint256 _goal, uint256 _durationInDays) {
creator = msg.sender;
goal = _goal;
deadline = block.timestamp + (_durationInDays * 1 days);
}
// Function to contribute to the campaign
function contribute() public payable {
require(block.timestamp < deadline, "Campaign ended");
require(msg.value > 0, "Contribution must be greater than zero");
contributions[msg.sender] += msg.value;
totalFunds += msg.value;
emit ContributionReceived(msg.sender, msg.value);
}
// Function for the creator to withdraw funds if the goal is reached
function withdrawFunds() public onlyCreator {
require(totalFunds >= goal, "Funding goal not reached");
require(block.timestamp >= deadline, "Campaign still active");
goalReached = true;
payable(creator).transfer(totalFunds);
emit FundsWithdrawn(creator, totalFunds);
}
// Function to refund contributors if the goal is not met
function refund() public {
require(block.timestamp >= deadline, "Campaign still active");
require(totalFunds < goal, "Funding goal reached");
uint256 amount = contributions[msg.sender];
contributions[msg.sender] = 0;
payable(msg.sender).transfer(amount);
emit RefundIssued(msg.sender, amount);
}
// Function to get the campaign details
function getCampaignDetails() public view returns (address, uint256, uint256,
uint256, bool) {
return (creator, goal, deadline, totalFunds, goalReached);
}
}
https://drive.google.com/file/d/1G-_ckhcAHjrl4ZuJr5BjkadkXWjdfSzZ/view?usp=sharing
Gas Usage
https://docs.google.com/spreadsheets/d/1GbKZ9xDCPzDR_wRw42lPxhBxoc7yYz3r?
rtpof=true&usp=drive_fs
https://drive.google.com/open?id=1GbtWtDiypsmEVc7dzx3TmU_cIQPbGDex&usp=drive_fs
134
Gas Usage
1. Contract Deployment
The insurer (contract deployer) pays the gas fees for deploying the contract.
Gas Usage:
1) Storage variables like insurer, flightNumber, delayThreshold, payoutAmount, and
transactionFee are initialized.
2) Constructor Execution
2. Setting the Premium
The insurer pays the gas fees when calling the setPremium function to set or update
the policy premium.
Gas Usage:
1) Validation: require checks ensure that only the insurer can set the premium.
2) Storage Update: Writing the new premium value to the blockchain's storage.
135
Gas Usage
3. Purchasing a Policy
The policyholder (customer) pays the gas fees when calling the purchasePolicy
function and sends the premium + transactionFee.
Gas Usage:
1) Validation: require checks ensure the correct payment amount (msg.value ==
premium + transactionFee) and that no policyholder exists.
2) Storage Updates: The policyholder variable is updated with the caller’s address.
3) Emitting an Event: The PolicyPurchased event is logged.
4. Triggering a Payout
The insurer pays the gas fees when calling the triggerPayout function to issue the
payout to the policyholder.
Gas Usage:
1) Validation: require checks ensure the caller is the insurer, the payout hasn't
been claimed, and the delay meets or exceeds the threshold.
2) Storage Updates: The isClaimed flag is set to true.
3) Ether Transfer: The payoutAmount is transferred to the policyholder.
4) Emitting an Event: The PayoutIssued event logs the payout details.
136
Gas Usage
5. Fallback Function (receive)
The sender of Ether (anyone sending Ether to the contract) pays the gas fees.
Gas Usage
1) Base Ether Transfer: The contract accepts the Ether without additional
computation.
137
Block in Ethereum
138
https://www.blockchain.com/explorer/blocks/eth/21212682
Block in Ethereum
Hash: A cryptographic identifier generated using the Keccak-256 hash function.
The block hash is produced by hashing various components of the block (like
transactions, state root, timestamp, nonce, etc.). This hash must meet the
difficulty level set by the network to be accepted as a valid block. The hash
ensures the block’s integrity and immutability.
Parent Hash: The hash of the immediately preceding block in the blockchain.
This field connects the current block to the previous one, forming a chain of
blocks. If any previous block changes, it will alter its hash, breaking the link.
This mechanism is crucial for ensuring the immutability of the blockchain.
Sha3Uncles: The Keccak-256 hash of the "uncles" included in the block.
Uncles (or ommer blocks) are valid blocks that were mined almost simultaneously
with the current block but did not get included in the main chain. The hash of
these uncles is stored to acknowledge their contribution to the network, rewarding
miners with partial incentives.
State Root: The root hash of the Merkle Patricia Trie that stores the entire state
of Ethereum (including account balances, contract storage, and more).
As transactions are processed, the state of Ethereum changes. These changes are
recorded in a state tree, and the root of this tree is stored as the state root. It
ensures that every state change is verifiable and tamper-proof.
Nonce: A 64-bit cryptographic number that miners adjust to find a valid block hash.
The nonce is used in the Proof-of-Work (PoW) process. Miners increment this nonce
to alter the resulting block hash until it satisfies the network’s difficulty
target, producing a valid block.
139
Block in Ethereum
Depth: The number of blocks mined after this particular block.
A greater depth indicates that the block is deeply embedded in the blockchain,
making it harder to alter. In Ethereum, the more confirmations a block has, the
more secure it is considered.
Capacity: The proportion of the block's gas limit that is used by the transactions.
Blocks have a maximum gas limit (set by miners), which determines how many
transactions can fit within a block. Capacity shows how efficiently this space is
utilized.
Distance: The time interval between this block and its preceding block.
Ideally, Ethereum aims for a block time of around 12-14 seconds. This distance can
vary due to network congestion, difficulty adjustments, and other factors.
Mined: The timestamp indicating when the block was mined, stored in Unix epoch time
format.
This timestamp is critical for transaction ordering and block validation. It also
affects the difficulty adjustment algorithm.
Miner: The Ethereum address of the miner who successfully mined the block.
The miner receives the block reward (newly minted Ether) and any transaction fees
associated with the transactions included in the block. The miner’s address is
specified to receive these incentives.
140
Block in Ethereum
Transactions: The count of transactions included in the block.
Each transaction is recorded in a Merkle Tree, whose root hash is stored in the
block header for efficient verification.
Internal Txs (Internal Transactions): Function calls and value transfers executed
by smart contracts.
Unlike regular transactions, internal transactions are not explicitly recorded on-
chain but occur as part of contract execution. They are logged as “internal
transactions” during contract interactions.
Sent: The total amount of Ether sent in all transactions within the block.
This value is a sum of all outgoing Ether transfers. It does not include gas fees,
only the value transferred between addresses.
Internal Value: The USD equivalent of the total Ether sent through internal
transactions.
This value is determined using the current exchange rate at the time of querying
the blockchain data.
Value Today: The current market value of the total Ether sent in this block,
converted to USD.
It is calculated based on the latest exchange rate for Ether, showing the
equivalent value of the Ether transfers at current market prices.
141
Block in Ethereum
Average Value: The average amount of Ether transferred per transaction.
This is derived by dividing the total Ether sent by the number of transactions in
the block.
Median Value: The middle value of all Ether transfers in the block when sorted.
The median provides a measure that is less affected by outliers compared to the
average.
Block Reward: The reward (in Ether) given to the miner for successfully mining the
block.
The block reward includes a fixed reward (2 ETH in Ethereum currently) plus any
transaction fees paid by users for transactions included in the block.
Minted: Indicates whether new Ether was created as part of the block reward.
In Ethereum’s PoW model, new Ether is minted as a reward for miners. The transition
to Proof-of-Stake (PoS) has reduced this significantly.
Difficulty: A measure of how hard it is to mine a new block.
Ethereum’s difficulty is adjusted periodically to ensure that blocks are mined
approximately every 12-14 seconds. A higher difficulty means more computational
power is required.
142
Block in Ethereum
Total Difficulty: The cumulative sum of the difficulty of all blocks mined up to
this point.
It represents the total work done by miners to secure the blockchain since its
inception.
Gas: The total amount of gas used by all transactions in the block.
Gas is a unit that measures the amount of computational work required to execute
operations. It limits the number of transactions that can fit within a block.
Gas Limit: The maximum amount of gas allowed for all transactions in a single
block.
The gas limit can be adjusted by miners to control the block size. A higher gas
limit allows more complex transactions but increases the risk of network
congestion.
Fee Reward: The total amount of gas fees collected by the miner from all
transactions in the block.
This is the sum of gas fees paid by users for their transactions. It incentivizes
miners to include more transactions in a block.
Size: The physical size of the block in bytes.
It includes the data of all transactions, receipts, and other metadata. Blocks have
a maximum size limit based on the gas limit, which indirectly controls the number
of transactions a block can accommodate.
143
Block in Ethereum
Total Difficulty: The cumulative sum of the difficulty of all blocks mined up to
this point.
It represents the total work done by miners to secure the blockchain since its
inception.
Gas: The total amount of gas used by all transactions in the block.
Gas is a unit that measures the amount of computational work required to execute
operations. It limits the number of transactions that can fit within a block.
Gas Limit: The maximum amount of gas allowed for all transactions in a single
block.
The gas limit can be adjusted by miners to control the block size. A higher gas
limit allows more complex transactions but increases the risk of network
congestion.
Fee Reward: The total amount of gas fees collected by the miner from all
transactions in the block.
This is the sum of gas fees paid by users for their transactions. It incentivizes
miners to include more transactions in a block.
Size: The physical size of the block in bytes.
It includes the data of all transactions, receipts, and other metadata. Blocks have
a maximum size limit based on the gas limit, which indirectly controls the number
of transactions a block can accommodate.
144
How a block is created
Transactions are created and sent to the network.
Miners collect these transactions into a block.
Miners solve the Proof-of-Work puzzle by adjusting the nonce.
A valid block is found and broadcasted to the network.
Other nodes validate the block.
The successful miner receives a reward (2 ETH + transaction fees).
The blockchain state is updated with new balances and contract data.
The network reaches consensus, and the block is added to the blockchain.
145
How a block is created
New Transactions are Created and Broadcasted
Users initiate transactions by sending Ether or interacting with smart contracts.
Each transaction includes data such as the sender's address, recipient's address,
value transferred, and gas fees.
These transactions are signed with the user's private key and then broadcasted to
the Ethereum network where nodes validate and propagate them.
Nodes validates 1) Nonce Check, 2) Signature Verification, 3) Sufficient Balance,
4) Gas Limits.
2. Transactions are Added to the Mempool
The mempool (memory pool) is a temporary storage area where all pending
transactions wait to be included in a block.
Priority Ranking in Mempool: 1) High-Priority Pool having transactions with high
gas prices, 2) Low-Priority Pool having transactions with lower gas prices.
Miners monitor the mempool for new transactions and select transactions based on
the gas fees attached to them (higher gas fees usually get prioritized).
146
How a block is created
3. Miners Assemble a Block
Miners gather transactions from the mempool to create a new block.
The miner includes as many transactions as possible within the block gas limit
(currently set at around 30 million gas).
The miner calculates the Merkle root of the transactions to create a single hash
representing all the transactions in the block.
The miner then constructs the block header, which contains:
Parent Hash: Hash of the previous block.
Sha3Uncles: Hash of the uncle blocks (blocks mined almost simultaneously).
State Root: The root hash of the Merkle Patricia Trie representing the current
state of Ethereum.
Transactions Root: The Merkle root of the transactions included in the block.
Receipts Root: The Merkle root of the receipts of all transactions.
Difficulty: The current difficulty target.
Number: The block number.
Gas Limit and Gas Used: Limits on transaction gas and the gas consumed by the
block.
Timestamp: The Unix timestamp of block creation.
Nonce: A random value miners change to find a valid hash.
147
How a block is created
148
How a block is created
6. Block Rewards and Transaction Fees
The miner who successfully mined the block is rewarded.
The block reward is currently 2 ETH (though this may change in future protocol
updates).
The miner also receives all the gas fees associated with the transactions included
in the block.
In addition, if the block includes uncle blocks, the miner receives an extra reward
for including them.
7. Updating the State
After the block is added to the blockchain, the global state of Ethereum is
updated.
The State Root stored in the block header represents the new state of the
blockchain after processing all transactions.
Ethereum’s state is stored in a Merkle Patricia Trie, which ensures efficient and
secure data storage.
Every account balance, contract storage, and variable change are recorded in the
new state.
149
How a block is created
7. Updating the State
What is the State in Ethereum?
1) Account State:
External Accounts (EOAs): User-controlled accounts with balances and nonces.
Contract Accounts: Accounts with associated code and storage.
2) Global Storage: Data stored by smart contracts.
3) Blockchain State: The cumulative result of all executed transactions since the
genesis block.
The state is stored as a Merkle Patricia Trie, a cryptographically secure data
structure.
150
How a block is created
8. Consensus and Finality
The network reaches consensus on the latest state of the blockchain.
In PoW, the longest chain with the most cumulative difficulty is considered the
valid chain.
Nodes continuously validate new blocks to ensure they adhere to the consensus
rules.
Finality in Ethereum is probabilistic; a block is considered "final" after it has
accumulated a certain number of confirmations (usually after 12-15 blocks).
151
Merkle Patricia Tree in Ethereum
The Merkle Patricia Tree (MPT) is a key data structure in Ethereum, used to store
and efficiently manage the blockchain's state.
It combines the properties of a Merkle tree and a Patricia trie to provide
efficient, secure, and tamper-proof state management.
Uses of the Merkle Patricia Tree in Ethereum
Global State Storage: Stores the state of all accounts (balances, contract storage,
code, and nonces).
Transaction Receipts: Keeps transaction results and logs.
Transaction Data: Organizes transactions included in a block.
Each Ethereum block header includes:
State Root: The root hash of the MPT representing the global state.
Transaction Root: The root hash of the MPT for transactions in the block.
Receipts Root: The root hash of the MPT for transaction receipts.
152
Merkle Patricia Tree in Ethereum
Global State MPT: Manages the state of accounts and contracts.
Transactions MPT: Organizes all transactions in a block.
Receipts MPT: Tracks the outcomes of transactions (receipts).
153
Merkle Patricia Tree in Ethereum
1. MPT Representing the Global State
The Global State MPT represents the current state of all accounts and contracts on
Ethereum, including:
Account balances, Nonces (transaction counts), Smart contract code, Smart contract
storage (stored in a separate MPT for each contract).
2. MPT for Transactions in an Ethereum Block
The Transactions MPT represents all transactions included in a specific block. It
ensures:
Tamper-proof organization of transactions, Efficient verification that a
transaction belongs to a block.
3. MPT for Transaction Receipts
The Receipts MPT tracks the outcomes of all transactions in a block, storing
details like:
Whether a transaction succeeded or failed.
Gas used by the transaction.
Events (logs) emitted during execution.
154
MPT representing the global state
The global state in Ethereum consists of:
Externally Owned Accounts (EOAs): Contains account balances, nonces, and other
data.
Smart Contract Accounts: Contains contract code and the contract's storage.
Each account's state is represented as a key-value pair:
Key: The account address (160-bit hexadecimal string).
Value: The account details, which include: Balance (in wei), Nonce (transaction
count), CodeHash (hash of the contract's code, if it's a contract), StorageRoot
(root hash of another MPT for contract storage)
155
MPT representing the global state
Leaf Node: Represents an account or a contract's state.
E.g. Key: 0xabc123, Value: {balance: 10 ETH, nonce: 5, codeHash: ...,
storageRoot: ...}
Branch Node: Has up to 16 children, one for each hexadecimal character (0–f).
E.g. Branch[3]: Points to a subtree for all keys starting with "3".
Extension Node: Compresses a long path with shared prefixes.
E.g. Path: "12ef" → Points to a deeper node or value.
156
MPT representing the global state
Example: Representing Global State
Consider three accounts:
1. Address 0xabc123:
Balance: 10 ETH.
Nonce: 5.
CodeHash: 0xdead... (if it's a contract).
StorageRoot: 0xbeef... (contract storage, if applicable).
2. Address 0xdef456:
Balance: 20 ETH.
Nonce: 3.
3. Address 0x123789:
Balance: 15 ETH.
Nonce: 4.
157
MPT representing the global state
Building the MPT:
1. Hexadecimal Keys:
Split the address keys into nibbles:
0xabc123 → a → b → c → 1 → 2 → 3.
0xdef456 → d → e → f → 4 → 5 → 6.
0x123789 → 1 → 2 → 3 → 7 → 8 → 9.
3. Branch Nodes:
Branch Node:
Key "a" → Subtree for "abc123".
Key "d" → Subtree for "def456".
Key "1" → Subtree for "123789".
Root Hash:
Root Hash = Hash(Hash(Branch Node for "a") + Hash(Branch Node for "d") +
Hash(Branch Node for "1")).
158
2. Leaf Nodes:
Leaf for "abc123": {balance: 10 ETH, nonce: 5, ...}
Leaf for "def456": {balance: 20 ETH, nonce: 3, ...}
Leaf for "123789": {balance: 15 ETH, nonce: 4, ...}
MPT representing the global state
159
Root (Hash)
|
|-- "a" → Extension Node ("bc")
| |-- Branch Node ("123")
| |-- Leaf Node: {balance: 10 ETH, nonce: 5, ...}
|
|-- "d" → Branch Node ("ef")
| |-- Leaf Node: {balance: 20 ETH, nonce: 3, ...}
|
|-- "1" → Extension Node ("23")
|-- Leaf Node: {balance: 15 ETH, nonce: 4, ...}
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
In Ethereum, the Merkle Patricia Tree (MPT) is used to organize and manage the
transactions in a block.
Each Ethereum block contains a transaction root in its header, which is the root
hash of the MPT representing all transactions in that block.
This structure allows for efficient verification, inclusion proofs, and state
updates while maintaining tamper-proof integrity.
Key-Value Pairs:
Key: The index of the transaction in the block (e.g., 0, 1, 2 for the 1st, 2nd, and
3rd transactions).
Value: The transaction data (e.g., sender, recipient, value, gas).
160
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
Example Transactions:
Transaction 1:
- Sender: 0xabc123.
- Recipient: 0xdef456.
- Value: 5 ETH.
Transaction 2:
- Sender: 0x123789.
- Recipient: 0x456abc.
- Value: 10 ETH.
161
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
Tree Structure: The key is converted into a path in the MPT.
For example:
Transaction 0 → Path: 0.
Transaction 1 → Path: 1.
The value (transaction data) is stored at the corresponding leaf node.
Branch nodes are created to manage shared prefixes, and hashes are computed
recursively to form the root hash.
162
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
Building the Transaction MPT
1. Convert Transaction Indexes to Paths:
Index 0 → Path: "0"
Index 1 → Path: "1"
Index 2 → Path: "2"
2. Create Leaf Nodes: Each leaf node contains the transaction data.
Leaf for "0": {sender: 0xabc123, recipient: 0xdef456, value: 5 ETH}
Leaf for "1": {sender: 0x123789, recipient: 0x456abc, value: 10 ETH}
3. Create Branch Nodes: Branch nodes group transactions with common prefixes.
4. Compute Hashes: Starting from the leaf nodes, recursively hash the data up to
the root.
163
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
Example:
Transaction 0: Sender: 0xabc123, Recipient: 0xdef456, Value: 5 ETH.
Transaction 1: Sender: 0x123789, Recipient: 0x456abc, Value: 10 ETH.
Transaction 2: Sender: 0xdef456, Recipient: 0x789abc, Value: 2 ETH.
MPT Construction
Step 1: Convert Indexes to Paths
Transaction 0 → Path: "0"
Transaction 1 → Path: "1"
Transaction 2 → Path: "2"
Step 2: Create Leaf Nodes
Leaf for "0": Hash({sender: 0xabc123, recipient: 0xdef456, value: 5 ETH})
Leaf for "1": Hash({sender: 0x123789, recipient: 0x456abc, value: 10 ETH})
Leaf for "2": Hash({sender: 0xdef456, recipient: 0x789abc, value: 2 ETH})
164
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
Example:
Step 3: Create Branch Nodes
Branch Node:
"0" → Leaf for "0".
"1" → Leaf for "1".
"2" → Leaf for "2".
Step 4: Compute Root Hash
Root Hash = Hash(Hash(Leaf for "0") + Hash(Leaf for "1") + Hash(Leaf for "2"))
165
Merkle Patricia Tree (MPT) for Transactions in an Ethereum Block
166
Root (Hash)
|
|-- "0" → Leaf Node: {sender: 0xabc123, recipient: 0xdef456, value: 5 ETH}
|
|-- "1" → Leaf Node: {sender: 0x123789, recipient: 0x456abc, value: 10 ETH}
|
|-- "2" → Leaf Node: {sender: 0xdef456, recipient: 0x789abc, value: 2 ETH}
MPT for transaction receipts
In Ethereum, the Merkle Patricia Tree (MPT) is used to represent the transaction
receipts within a block.
Each block contains a receipts root in its header, which is the root hash of the
MPT encapsulating all transaction receipts in that block.
This structure ensures that the receipts are tamper-proof and efficiently
verifiable.
A transaction receipt is a record of what happened when a transaction was executed.
It includes details about the transaction's execution and its effects.
Key Fields in a Transaction Receipt
1) Transaction Hash: Unique identifier for the transaction.
2) Status: Success (1) or failure (0).
3) Cumulative Gas Used: The total gas used by this and all previous transactions in
the block.
4) Logs: Events emitted during the execution (e.g., smart contract events).
5) Bloom Filter: A compact representation of all logs in the transaction, used for
log searches.
167
MPT for transaction receipts
Purpose of the Transaction Receipts MPT
Tamper Resistance: Ensures that any modification to a receipt changes the root
hash, making tampering detectable.
Efficient Verification: Allows cryptographic proofs to verify whether a receipt
belongs to a block.
Compact Storage: Organizes and compresses receipt data for efficient storage and
retrieval.
168
MPT for transaction receipts
Key-Value Pairs
In the receipts MPT:
Key: The index of the transaction in the block (e.g., 0, 1, 2).
Value: The transaction receipt data.
1) Transaction 0:
Key: 0
Value: {hash: 0xabc123, status: 1, cumulativeGas: 21000, logs: [...], bloom: 0x...}
2) Transaction 1:
Key: 1
Value: {hash: 0xdef456, status: 0, cumulativeGas: 45000, logs: [...], bloom: 0x...}
Tree Structure
The key (transaction index) is converted into a path in the MPT.
Example: Transaction 0 → Path: 0, Transaction 1 → Path: 1.
The value (receipt data) is stored at the corresponding leaf node.
169
MPT for transaction receipts
Building the Receipts MPT
1) Convert Transaction Indexes to Paths:
Transaction 0 → Path: "0"
Transaction 1 → Path: "1"
Transaction 2 → Path: "2"
2) Create Leaf Nodes:
Each leaf node contains the receipt data.
Leaf for "0": {hash: 0xabc123, status: 1, cumulativeGas: 21000, logs: [...]}
Leaf for "1": {hash: 0xdef456, status: 0, cumulativeGas: 45000, logs: [...]}
3) Create Branch Nodes: Branch nodes group receipts with common prefixes.
4) Compute Root Hash: Starting from the leaf nodes, recursively compute hashes to
form the root hash.
170
MPT for transaction receipts
Example
Receipts
Receipt 0:
Transaction Hash: 0xabc123.
Status: Success (1).
Cumulative Gas: 21000.
Logs: ["Transfer event"].
Bloom Filter: 0x01....
Receipt 1:
Transaction Hash: 0xdef456.
Status: Failed (0).
Cumulative Gas: 45000.
Logs: ["Approval event"].
171
Receipt 2:
Transaction Hash: 0x789abc.
Status: Success (1).
Cumulative Gas: 62000.
Logs: ["Token Minted"].
MPT for transaction receipts
MPT Construction
Step 1: Convert Indexes to Paths
Receipt 0 → Path: "0"
Receipt 1 → Path: "1"
Receipt 2 → Path: "2"
Step 2: Create Leaf Nodes
Leaf for "0": Hash({hash: 0xabc123, status: 1, cumulativeGas: 21000, logs: [...]})
Leaf for "1": Hash({hash: 0xdef456, status: 0, cumulativeGas: 45000, logs: [...]})
Leaf for "2": Hash({hash: 0x789abc, status: 1, cumulativeGas: 62000, logs: [...]})
Step 3: Create Branch Nodes
Branch Node:
"0" → Leaf for "0".
"1" → Leaf for "1".
"2" → Leaf for "2".
Step 4: Compute Root Hash
Root Hash = Hash(Hash(Leaf for "0") + Hash(Leaf for "1") + Hash(Leaf for "2"))
172
MPT for transaction receipts
173
Root (Hash)
|
|-- "0" → Leaf Node: {hash: 0xabc123, status: 1, cumulativeGas: 21000, logs:
[...]}
|
|-- "1" → Leaf Node: {hash: 0xdef456, status: 0, cumulativeGas: 45000, logs:
[...]}
|
|-- "2" → Leaf Node: {hash: 0x789abc, status: 1, cumulativeGas: 62000, logs:
[...]}
Uncle block
The canonical chain is the longest and most authoritative chain of blocks in the
Ethereum network. It is the agreed-upon sequence of blocks by all participants in
the network.
A canonical block is a valid block that is accepted as part of the canonical chain.
It represents the final, agreed-upon block for a given position in the blockchain.
What is a Fork? A fork occurs when two or more blocks are mined or proposed
simultaneously, creating competing versions of the blockchain.
Resolving Forks in PoW
1) Longest Chain Rule: The chain with the highest cumulative difficulty is chosen
as the canonical chain.
2) Orphan Blocks: Blocks in losing chains become orphan blocks and are discarded.
3) Uncle Blocks: Valid blocks that are not part of the canonical chain but are
referenced by other blocks.
Return to the Mempool: If an uncle block’s transactions are not included in the
canonical chain, they return to the mempool, a queue of unconfirmed transactions
available to all miners.
174
Uncle block
An uncle block (also called an ommer block) is a valid block in the Ethereum
blockchain that is mined almost simultaneously as the canonical block (the block
that becomes part of the main blockchain) but does not get included in the main
chain due to timing or network latency.
Ethereum rewards miners for uncle blocks to incentivize decentralization and
mitigate the disadvantages smaller miners might face.
Key Features of Uncle Blocks
Validity: An uncle block is valid and meets all consensus rules but is not included
in the canonical blockchain.
Cause: Uncle blocks occur because Ethereum's block time is relatively short (~12
seconds), so two miners might solve a block at nearly the same time.
Reward: Uncle blocks are rewarded to the miner to encourage participation and
secure the network.
Inclusion: Uncle blocks can be referenced by a later canonical block to improve
network efficiency and security.
175
Uncle block
Uncle Blocks vs. Orphan Blocks
Uncle Blocks: Referenced by the canonical chain. Contribute to network security and
decentralization.
Orphan Blocks: Not referenced by the canonical chain. Do not provide security or
rewards.
How Uncle Blocks Are Created
Two miners solve a block at nearly the same time.
The network propagates both blocks.
One block is accepted as part of the canonical chain based on the longest chain
rule or fork-choice rule.
The other block becomes an uncle block if it meets the following conditions:
It is a valid block.
It was mined recently (within six generations of the canonical chain).
Rewards for Uncle Blocks
The miner of the uncle block receives a reward proportional to how close the uncle
block is to the canonical chain:
The miner of the canonical block that references the uncle block also gets a small
reward.
176
Uncle block
Scenario
Step 1: Initial Blockchain State: Block 99 --> Block 100 (Canonical Chain Head)
Step 2: Two Miners Mine Simultaneous Blocks
Miner A mines Block 101-A:
Transactions: Tx1, Tx2, Tx3.
Hash: 0xabc123.
Parent Block: Block 100.
Block Height: 101.
Miner B mines Block 101-B:
Transactions: Tx4, Tx5, Tx6.
Hash: 0xdef456.
Parent Block: Block 100.
Block Height: 101.
Both blocks are valid and reference the same parent (Block 100). Due to network
latency, different parts of the Ethereum network may temporarily accept either
block as the next block.
Step 3: Canonical Chain Selection
A third miner, Miner C, creates Block 102.
Block 102 references Block 101-A as its parent: Block 100 --> Block 101-A --> Block
102
Block 101-A becomes part of the canonical chain because it is extended first.
177
Uncle block
Scenario
Step 4: Block 101-B Becomes an Uncle
Block 101-B is valid but not part of the canonical chain.
Miner C includes Block 101-B as an uncle block in Block 102.
178
Uncle block
179
Uncle block
180
Difficulty Adjustment
Average Block Time in Ethereum: Approximately 12–14 seconds.
Prevent Block Rate Instability:
If the hash rate increases (e.g., due to more miners joining), blocks would
otherwise be mined faster.
If the hash rate decreases (e.g., due to miners leaving), blocks would otherwise be
mined slower.
Adapt to Network Conditions: Dynamically adjusts difficulty to match real-time
changes in the network's hash rate.
181
Difficulty Adjustment
182
Difficulty Adjustment
183
References
https://www.youtube.com/watch?v=RQzuQb0dfBM
https://www.youtube.com/watch?v=EhPeHeoKF88
https://www.youtube.com/watch?v=AYpftDFiIgk
184
References
Bashir, I. (2017). Mastering blockchain. Packt Publishing Ltd.
Antonopoulos, A.M. and Wood, G., 2018. Mastering ethereum: building smart contracts
and Dapps. O'reilly Media.
185