Encode Club: Nethermind Workshop EVM Bootcamp

lara348812 145 views 47 slides Sep 18, 2024
Slide 1
Slide 1 of 47
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47

About This Presentation

Slides for the Nethermind Workshop from the EVM Bootcamp (Week 26).


Slide Content

EVM Bootcamp
Yehia

Introductions
●I’m Yehia
●Blockchain Engineer at Nethermind
●Specialize in Dapps Development
●I build DeFi solutions

●Why EVM
●What is EVM
●Instructions Executions
●Ethereum State: Account,trie
transaction and receipt State
●Blocks

What we will cover

●Gas Optimization
●Solidity will make sense only if you
understand EVM
●Advanced smart contract design
patterns
Why Learn EVM

What is EVM

What is EVM
CPU Machines


Over the decades, CPUs have been highly, highly optimized for
speed of execution. They can execute instructions fast –
trillions per second fast. That's a lot of instructions.
Ethereum Virtual Machine
A virtual machine is a software program designed to behave like a
physical machine. That is, it's software that – like a CPU – reads,
interprets, and executes instructions.

The EVM is no different. It reads, interprets, and executes instructions
encoded in a smart contract's bytecode. The tangible result from
executing these instructions is updating contract state and returning
data.

EVM Instructions

EVM Instructions - Program Counter
-The PC is a 256-bit integer that points to
the current instruction in the EVM code.

-It starts at 0 and increments by 1 after
each instruction (unless modified by a
JUMP instruction).

-The PC determines which opcode in the
EVM code will be executed next.

EVM Instructions - EVM Code
-This is the bytecode of the smart
contract or the data payload of a
transaction.


-It's a series of opcodes and their
arguments.

-Each opcode is one byte (8 bits) long,
represented by a hexadecimal value (e.g.,
0x01 for ADD).

EVM Instructions - EVM Code (examples)

-Arithmetic Opcodes: ADD, MUL, DIV (and
more) allow for the computation of
arithmetic operations

-Control Flow Opcodes: JUMP, JUMPI (and
more) enable conditional and
unconditional branching

-Memory and Storage Management
Opcodes MLOAD, SLOAD, SSTORE (and
more): There are different opcodes
depending on the instruction, such as
SSTORE, SLOAD, MSTORE, MLOAD and
several more

EVM Instructions - EVM Code (examples)

-New opcodes that are specific to the
Ethereum environment itself:
-CREATE: This opcode creates a new
smart contract based on the code
provided. This uses a larger gas amount
and is variable depending on the
bytecode being deployed.
-BLOCKHASH: This opcode is the hash of
one of the 256 most recent complete
blocks
-BALANCE: Returns the balance of a given
account
-CALL: A system operation which consists
of a message-call (read operation) into
an account

EVM Instructions - Operations (Gas)
-The EVM reads the opcode at the current
PC.
-Each opcode has a predefined gas cost.
-Before execution, the EVM checks if
there's enough gas. If not, it throws an
"Out of Gas" exception.
-The gas cost is deducted from the
remaining gas.
-The operation is then executed, which
may involve:
-> Manipulating the stack
-> Reading from or writing to memory
-> Accessing account storage
-> Performing arithmetic or logical
operations

EVM Instructions - Message Call (Gas)
If the opcode is a CALL, DELEGATECALL, or
STATICCALL:

-Additional gas is required for the call
itself and for any value transfer.

-A new execution context is created (with
its own PC, memory, and stack).

-The called contract's code is loaded and
executed.

-Any remaining gas is returned to the
caller after the call completes.

EVM Instructions- The Stack
Stack

- Most operations involve the stack (e.g.,
PUSH, POP, SWAP, DUP).

- Stack operations are generally cheap in
terms of gas. All opcode cost 3 gas

- The stack is limited to 1024 elements.

EVM Instructions- Memory

Memory
- Operations like MLOAD, MSTORE involve
memory.

- Memory expansion incurs additional gas
costs.

- MLOAD and MSTORE cost is 3 gas

- Gas cost increases quadratically with
memory size. (complex operation sha3, size or
unused memory)

EVM Instructions - Storage
Storage

-Storage operations are the most
expensive in terms of gas.

- SLOAD and SSTORE opcodes access
account storage.

-SSTORE can cost 20,000 gas for a new
storage slot, or 5,000 gas for updating
an existing slot.

-SLOAD costs 2100 gas to initially access
a value during a transaction and costs
100 gas for each subsequent access

EVM Instructions - Storage (example)



contract MyContract {
uint32 a; // First slot
uint64 b; // First slot
uint128 c; // First slot
uint64 d; // Second slot
uint256 e; // Third slot
}

EVM Instructions- The Stack Too Deep Issue
Stack Too Deep Issue

-Break function into smaller functions
-Use storage instead of memory for large
arrays/structs(rare case)
-Optimize local variable usage
-Reduce function parameters
-Use external instead of public for
functions
-Use libraries for complex operations

EVM Instructions- The Stack Too Deep Issue
Stack Too Deep Issue

-Use events to store non-critical data
-Use assembly for gas-intensive
operations
-Implement batching for multiple
operations
-Use mapping instead of arrays where
possible
-Use short-circuiting in logical operations

EVM Instruction - Flow Part One
1.The EVM reads the opcode at the current
PC.
2.It checks if there's enough gas for the
operation.
3.If sufficient gas, it deducts the base cost
of the operation.
4.The operation is executed:
-For stack operations: Elements are
pushed, popped, or manipulated.
-For memory operations: Data is read
from or written to memory.
-For storage operations: The contract's
storage is read or updated.

EVM Instructions - Flow Part Two
1.If the operation involves memory
expansion or storage modification,
additional gas is consumed.
2.For CALL operations, a new execution
context is created, and the process
resources.
3.The PC is incremented (unless it's a JUMP
operation).
4.This process repeats until:
- The code execution completes
successfully.
-An error occurs (e.g., out of gas,
stack overflow).
-A STOP, RETURN, or REVERT opcode
is encountered.

Ethereum State
●Account State
●Transaction
●Transaction Receipt

Account State
Ethereum State Trie Architecture Explained

Merkle Particia Trie Ethereum Foundation

Transaction And Transaction Receipt Tries
Transaction Tries: records transaction request

Transaction Receipt Tries: records the transaction
outcome

Transaction Lifecycle
1.The transaction is created and signed by the sender.
2.The transaction is sent to a node that does the following:
i) Checks if the transaction is valid.
ii) Spins up a EVM instance.
iii) Load state from the database.(global variables, persistent storage)
iv) Executes the transaction:
a. Executes all the opcodes in the transaction.
b. Updates the state of the EVM.
c. Reduces the gas left for the transaction.
3.The transaction is added to the blockchain and the state is saved to the database, while the stack
and memory are wiped.

Transaction Components

to: DATA, 20 Bytes - address of the receiver. null when it's a contract creation transaction.
transactionIndex: QUANTITY - integer of the transactions index position in the block. null when it's
pending.
value: QUANTITY - value transferred in Wei.
v: QUANTITY - ECDSA recovery id
r: DATA, 32 Bytes - ECDSA signature r
s: DATA, 32 Bytes - ECDSA signature s

Transaction Receipt
The Transaction Trie is linked to the World State Trie and other tries through block hashes,
ensuring data integrity and immutability. Receipts are a data structure in which details regarding
the execution of every transaction within a specific block are recorded.

Transaction Receipt
The Transaction Trie is linked to the World State Trie and other tries through block hashes,
ensuring data integrity and immutability. Receipts are a data structure in which details regarding
the execution of every transaction within a specific block are recorded.

Transaction Receipt
blockHash: String, 32 Bytes - hash of the block where this transaction was in.
blockNumber: Number - block number where this transaction was in.
transactionHash: String, 32 Bytes - hash of the transaction.
transactionIndex: Number - integer of the transactions index position in the block.
from: String, 20 Bytes - address of the sender.
to: String, 20 Bytes - address of the receiver. null when its a contract creation transaction.
cumulativeGasUsed: Number - The total amount of gas used when this transaction was executed
in the block.
gasUsed: Number - The amount of gas used by this specific transaction alone.

Transaction Receipt

status: String - '0x0' indicates transaction failure , '0x1' indicates transaction succeeded.
contractAddress: String - 20 Bytes - The contract address created, if the transaction was a
contract creation, otherwise null.
logs: Array - Array of log objects, which this transaction generated.

Blocks

Blocks

The Block Fields
Field Description
slot the slot the block belongs to
proposer_indexthe ID of the validator proposing the block
parent_root the hash of the preceding block
state_root the root hash of the state object
body an object containing several fields, as defined below
There is a lot of information contained within a block. At the highest level a block
contains the following fields:

The Block Fields - The Body Field
Field Description
randao_reveal a value used to select the next block proposer
eth1_data information about the deposit contract(Deposit
root, deposit count and blockhash)
graffiti arbitrary data used to tag blocks
proposer_slash
ings
list of validators to be slashed
attester_slash
ings
list of attesters to be slashed

The Block Fields - The Body Field

receipts_root hash of the transaction receipts trie
logs_bloom data structure containing event logs
prev_randao value used in random validator selection
block_number the number of the current block
gas_limit maximum gas allowed in this block
gas_used the actual amount of gas used in this block
timestamp the block time
extra_data arbitrary additional data as raw bytes
base_fee_per_gasthe base fee value
block_hash Hash of execution block

Field Description
deposits list of new deposits to the deposit contract
voluntary_exits list of validators exiting the network
sync_aggregate subset of validators used to serve light clients
execution_payloadtransactions passed from the execution client
The Block Fields - The Body Field
attestations list of attestations in favor of the current block

The Block Fields
The attestations field contains a list of all the attestations in the block. Attestations have their own
data type that contains several pieces of data. Each attestation contains:
Field Description
aggregation_bitsa list of which validators participated in this attestation
data a container with multiple subfields
signature aggregate signature of all attesting validators

The Block Fields
The data field in the attestation contains the following:


Field Description
slot the slot the attestation relates to
index indices for attesting validators
beacon_block_rootthe root hash of the Beacon block containing this object
source the last justified checkpoint
target the latest epoch boundary block

The Block Fields
Executing the transactions in the execution_payload updates the global state. All clients
re-execute the transactions in the execution_payload to ensure the new state matches that in
the new block state_root field

Field Description
parent_hash hash of the parent block
fee_recipientaccount address for paying transaction fees to
state_root root hash for the global state after applying changes in this block

The Block Fields
transactions_root root hash of the transactions in the payload
withdrawal_root root hash of the withdrawals in the payload
The execution_payload itself contains the following (notice this is identical to the header
except that instead of the root hash of the transactions it includes the actual list of
transactions and withdrawal information) :



Field Description
parent_hash hash of the parent block
fee_recipientaccount address for paying transaction fees to

The Block Fields
Field Description
state_root root hash for the global state after applying changes in this block
receipts_root hash of the transaction receipts trie
logs_bloom data structure containing event logs
prev_randao value used in random validator selection
block_number the number of the current block
gas_limit maximum gas allowed in this block

The Block Fields
Field Description
gas_used the actual amount of gas used in this block
timestamp the block time
extra_data arbitrary additional data as raw bytes
base_fee_per_gasthe base fee value
block_hash Hash of execution block
transactions list of transactions to be executed
withdrawals list of withdrawal objects

The Block Fields
The withdrawals list contains withdrawal objects structured in the following way:


Field Description
address account address that has withdrawn
amount withdrawal amount
index withdrawal index value
validatorIndex validator index value

The Block Time
Block time refers to the time separating blocks. In Ethereum, time is divided up into twelve
second units called 'slots'. In each slot a single validator is selected to propose a block.
Assuming all validators are online and fully functional there will be a block in every slot,
meaning the block time is 12s. However, occasionally validators might be offline when called
to propose a block, meaning slots can sometimes go empty.

This implementation differs from proof-of-work based systems where block times are
probabilistic and tuned by the protocol's target mining difficulty. Ethereum's average block
time(opens in a new tab) is a perfect example of this whereby the transition from
proof-of-work to proof-of-stake can be clearly inferred based on the consistency of the new
12s block time.

The Block Size
Blocks themselves are bounded in size. Each block has a target size of 15 million gas but the
size of blocks will increase or decrease in accordance with network demands, up until the
block limit of 30 million gas (2x target block size). The block gas limit can be adjusted upwards
or downwards by a factor of 1/1024 from the previous block's gas limit. As a result, validators
can change the block gas limit through consensus. The total amount of gas expended by all
transactions in the block must be less than the block gas limit. This is important because it
ensures that blocks can’t be arbitrarily large. If blocks could be arbitrarily large, then less
performant full nodes would gradually stop being able to keep up with the network due to
space and speed requirements. The larger the block, the greater the computing power
required to process them in time for the next slot. This is a centralizing force, which is resisted
by capping block sizes.

Conclusion and questions

Thank you (:
Tags