We reject abstraction
We believe in bytecode
Bytecode is only true form
Let’s code with bytes now
So far, we’ve explored how the EVM reads bytecode, how it handles memory and storage, and how it controls program flow with jumps. But here’s a question we haven’t answered yet: what happens when you deploy a contract?
When you deploy a smart contract, you’re sending a special transaction where:
to = 0x0 (indicating contract creation)
data = <contract bytecode>
But that <contract bytecode> is not just the logic of your contract. It’s a complete program that runs once during deployment. This program:
Runs your constructor
Uses the RETURN
opcode to return the runtime code to the EVM
What the EVM stores to the blockchain is only the runtime code.
When you deploy a new contract, the calldata bytecode of that transaction is usually divided into two parts.
1. Init Code
This is the first part of the bytecode. It executes only once at deployment. It starts by running the constructor logic where it can do writes in the storage if needed. Then returns the actual runtime code using the RETURN
opcode.
When RETURN
is called in the constructor, the value returned becomes the runtime code that is stored on-chain at your contract’s address.
2. Runtime Code
This is the code that actually lives on-chain at your contract address and runs every time someone calls the contract.
It’s the part that responds to function calls, reads calldata, interacts with storage, emits events, and does all the real work.
You can think of it like the permanent body of your contract. The init code is a temporary wrapper that sets it up.
A typical structure of a innit code consists in loading the runtime code into memory and returning it.
PUSH1 <size> // Number of bytes to copy (runtime size)
PUSH1 <offset> // Starting point in bytecode
PUSH1 <dest> // Destination in memory (typically 0x00)
CODECOPY // Copy bytecode to memory
PUSH1 <size> // Return size
PUSH1 <dest> // Memory offset to return from
RETURN // Return runtime code to EVM
Let's take a look at a typical way of deploying a smart contract on chain.
Example deployment bytecode:
6038600C60003960386000F35F357F0DBE671F0000000000000000000000000000000000000000000000000000000014602F5760055F5260205FF35B60045F5260205FF3
Let's now look at a step by step code deployment execution.
In our example, the process was:
Copy 56 bytes from <contract bytecode> starting at offset 12
Place them at memory position 0
Return them, this becomes the runtime code
In more complex smart contracts init code can also perform storage intializations, calls to other contracts or even new contract deployments.
Now you know what happens behind the scene when a contract is deployed. Thanks for reading and see you next Tuesday for more bytes.
filosofiacodigo.eth and Cooldev1337