We reject abstraction
We believe in bytecode
Bytecode is the only true form
Let’s code with bytes now
In the last article we explored opcodes, the individual instructions the EVM executes. Today we’re tracing the two distinct journeys your contract takes: one when you deploy it, and another each time it’s called.
You start with a .sol
or .vy
file in Solidity or Vyper, defining functions, state variables and control flow in human-readable form. When you invoke solc
or vyper
, the compiler outputs EVM bytecode, a linear stream of one-byte opcodes plus any immediate data. That bytecode is split into a header segment, which runs once to set up constructor logic and write initial values into storage slots, and a runtime segment, the permanent code that lives at your contract’s address.
Deployment is its own transaction with to = 0x0
and data = <contract-bytecode>
. That transaction enters the network’s mempool, where nodes check nonce, gas limit and signature. When a block proposer includes it in a block, the EVM executes the header segment: it manipulates the stack, uses transient memory (a temporary byte array that persists only during each transaction) for intermediate data, and writes to persistent storage slots (32-byte keys in the global state). If init succeeds within the gas budget, the runtime segment is returned and stored at the new contract address. For this point forward your contract is now live on the blockchain.
cast
commandEach call to your contract is another transaction with to = <contract-address>
and data = <calldata>
. Again it joins the mempool for basic validation. After mempool validation, the EVM loads the stored runtime bytecode and runs it with three data regions:
Stack
for last-in, first-out temporary values,
Memory
for intra-transaction data (a byte array that resets every call), and
Storage
slots for persistent state (a mapping of 32-byte keys to 32-byte values).
Storage in Ethereum is organized using a data structure called the Merkle Patricia Trie, which is a specialized form of a Merkle tree. This trie efficiently encodes key-value pairs (such as storage slots or account data) into a compact structure where the root hash represents the entire global state. Every time a storage slot is updated, the corresponding MPT changes, resulting in a new root hash that reflects the updated state.
During contract execution, each opcode consumes a certain amount of gas. If the transaction runs out of gas, all changes made during the call are reverted, this includes the stack, the memory and the storage. But when execution succeeds, the changes to storage and the emitted logs are emitted. The state of Ethereum then updates in the following flow: the old state root and the calldata (which you can think of as input parameters) are processed by the contract’s runtime bytecode. This produces an execution trace, which results in a new state root. The updated root reflects the global state after the transaction and is used in the block’s final state commitment.
Upon successful execution, the node calculates a new state root, a Merkle Patricia commitment covering every account balance and storage slot. That root is embedded in the block header. Under Proof-of-Stake, validators propose and attest to blocks; peers re-execute the same bytecode to confirm the state root matches, then follow the fork-choice rule and finalized checkpoints to agree on one canonical chain. Once finalized, your deployment or function call is irreversible.
Now that you have a clear, step-by-step view of deployment versus execution and how each leads to a consensus-backed state, you’re ready to dive deeper into how contracts are constructed at the bytecode level. Subscribe here on paragraph and join us next Tuesday for more bytecode.