5/5
_Follow along with this video:_ --- Just as before, we should leverage evm.codes to assist in visualizing the steps our execution takes when calling our `GET_NUMBER_OF_HORSES` macro. Keep an eye on the panel detailing memory at the bottom of the page! The playground is going to need an updated bytecode for the playground. `huffc src/HorseStoreV1/HorseStore.huff --bin-runtime` Our runtime bytecode should look something like this now (it keeps growing, the more we add!): ``` 5f3560e01c8063cdfead2e1461001b578063e026c01714610022575b6004355f55005b5f545f5260205ff3 ``` Because we're performing a read-only operation (readNumberOfHorses) all that's required to be passed as `calldata` is our function selector `0xe026c017`, remember you can us the command `cast sig "readNumberOfHorses()"` to derive this signature. Click run and step through the execution of this function call. The first steps are the same as before, our function dispatcher will compare the passed function signature vs our application's _known_ function signatures to determine which logic to perform on the passed `calldata`. > **Note:** Simply loading our new bytecode and calling our `readNumberOfHorses` function may be a little uneventful - remember to first send calldata to **_set_** a number of horses! Your contract state should look something like this if you've stepped through the `updateNumberOfHorses` execution (using 7 as a passed parameter):  Let's step through the execution further and see how things perform. Looking at the opcodes added to our contract following our `readNumberOfHorses()` jump destination (`JUMPDEST`) we should see: 1. PUSH0 - pushes our desired storage slot to the top of the stack for reference - in our case 0 2. SLOAD - loads data from the storage slot on the top of the stack 3. PUSH0 - the bytes offset that we wish to apply to the data being loaded - in our case 0 4. MSTORE - loads into memory the data from SLOAD with the requested bytes offset 5. PUSH1 - pushes the number of bytes we desire to be accessed from memory to the top of the stack - in our case we're passing '20' or '0x20' - this is the hex value for 32 bytes, the entirety of data in our storage slot 6. PUSH0 - bytes offset of data accessed from memory, or where to begin reading from the data string - again in our case this is zero to capture everything 7. RETURN - returns the data from memory beginning at the offset on the top of the stack, the size of this data string is determined by our second item in the stack (32 bytes)  That's really all there is to it! Breaking down the operations of a contract step by step makes each execution clear and easy to understand!
Follow along with this video:
Just as before, we should leverage evm.codes to assist in visualizing the steps our execution takes when calling our GET_NUMBER_OF_HORSES macro. Keep an eye on the panel detailing memory at the bottom of the page!
The playground is going to need an updated bytecode for the playground. huffc src/HorseStoreV1/HorseStore.huff --bin-runtime
Our runtime bytecode should look something like this now (it keeps growing, the more we add!):
Because we're performing a read-only operation (readNumberOfHorses) all that's required to be passed as calldata is our function selector 0xe026c017, remember you can us the command cast sig "readNumberOfHorses()" to derive this signature.
Click run and step through the execution of this function call. The first steps are the same as before, our function dispatcher will compare the passed function signature vs our application's known function signatures to determine which logic to perform on the passed calldata.
Note: Simply loading our new bytecode and calling our
readNumberOfHorsesfunction may be a little uneventful - remember to first send calldata to set a number of horses!
Your contract state should look something like this if you've stepped through the updateNumberOfHorses execution (using 7 as a passed parameter):

Let's step through the execution further and see how things perform. Looking at the opcodes added to our contract following our readNumberOfHorses() jump destination (JUMPDEST) we should see:
PUSH0 - pushes our desired storage slot to the top of the stack for reference - in our case 0
SLOAD - loads data from the storage slot on the top of the stack
PUSH0 - the bytes offset that we wish to apply to the data being loaded - in our case 0
MSTORE - loads into memory the data from SLOAD with the requested bytes offset
PUSH1 - pushes the number of bytes we desire to be accessed from memory to the top of the stack - in our case we're passing '20' or '0x20' - this is the hex value for 32 bytes, the entirety of data in our storage slot
PUSH0 - bytes offset of data accessed from memory, or where to begin reading from the data string - again in our case this is zero to capture everything
RETURN - returns the data from memory beginning at the offset on the top of the stack, the size of this data string is determined by our second item in the stack (32 bytes)

That's really all there is to it! Breaking down the operations of a contract step by step makes each execution clear and easy to understand!
A detailed walkthrough of how the EVM processes opcodes - This lesson shows you a detailed step-by-step process of how the EVM executes opcodes in the context of reading data from storage. It shows you exactly how the opcodes interact with the stack and memory of the EVM.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
Assembly
Writing smart contracts using Huff and Yul
Ethereum Virtual Machine OPCodes
Formal verification testing
Smart contract invariant testing
Halmos, Certora, Kontrol
Security researcher
$49,999 - $120,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Guest lecturers:
Last updated on August 11, 2025
Duration: 30min
Duration: 4h 38min
Duration: 3h 57min
Duration: 1h 56min
Course Overview
About the course
Assembly
Writing smart contracts using Huff and Yul
Ethereum Virtual Machine OPCodes
Formal verification testing
Smart contract invariant testing
Halmos, Certora, Kontrol
Security researcher
$49,999 - $120,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Guest lecturers:
Last updated on August 11, 2025