Blockchain Skyscrapers (1)

Nouhaila Fellahi
The Innostation Publication
12 min readFeb 16, 2022

Not sure if you were alive back in the 1800s, but when I was (the good old days), the main problem in New York was how to host more people since citizens were flooding the city. Prices of everyday utilities started rising and roads started congesting and causing trouble for everyone.

The solution that they found was to “build-up”, and that was how skyscrapers came to be.

Let’s say you and your friend live in different skyscrapers. You still live in the same city, of course. You use the same subways and public transportation networks, frequent the same stores and obey the same rules and laws.

A skyscraper gives many different levels to a city, but there’s no way for you to live your entire life above the city without having at least a few interactions and connections in the ‘main level’ of the city.

This is how roll-ups can be described. Roll-ups can provide you with cheaper gas fees, larger bandwidth, and near nonexistent waiting times for transaction mining. If these features were included in a layer 1, it would have to sacrifice either decentralization or security because of something called the blockchain trilemma.

Think of the blockchain trilemma like the famous ‘life trilemma’ that everyone talks about, “you can only choose two

Life trilemma 😩

This is also a choice that roll-up developers have to make, but it’s choosing two out of decentralization, security, and scalability.

Roll-ups can defy this rule. As they are inherent to blockchains, they can profit from their security and decentralization while keeping things scalable enough for them to be useful to day-to-day users.

What are roll-ups?

When an account wants to move and perform some sort of transaction or activity on a roll-up, it sends the amount of funds it wants to hold on the ‘side-chain’ to a smart contract that ‘locks’ the funds in and ‘creates’, or mints them to that user’s account on the roll-up.

Remember, cryptocurrencies are just bits of 0’s and 1’s, meaning that funds can be “cloned” wherever needed without losing any value. There’s no physical or tangible value that we’re dealing with.

The biggest problem that roll-ups are trying to solve is to have transactions take up less computing power and less storage. Which consequently means larger bandwidth, shorter pending times for transactions, and cheaper gas fees.

Roll-ups help get rid of this problem by batch-processing thousands of requests off-chain. Once a certain batch of transactions (the size of the batch depends on the roll-up and its protocol), a ‘proof-of-transaction’ is submitted to the main chain as a single transaction. This proof comes in the form of a root hash or a zk-SNARK/zk-STARK. These proofs allow for the main chain to process all the transactions that happened on the layer of the roll-up, or off-chain, with the same amount of computation it would take to verify a single transaction.

There are two types of roll-ups, Optimistic roll-ups and ZK (zero-knowledge) roll-ups. Though I’ll only be talking about Optimistic roll-ups in this part of the series.

Optimistic roll-ups

Optimistic roll-ups are… well, optimistic. They assume that all transactions submitted are honest and aren’t made in order to falsely change the state of the blockchain.

They use something called fraud proofs to stop fraudulent transactions from being passed on and added to the main layer of the chain. We’ll talk more about those later…

Optimistic Rollups rely on using fraud proofs to prevent invalid state transitions from happening.

Optimism

Optimism, the company which invented the first EVM-compatible Optimistic Roll-up protocol, is worth using as an example to explain how Optimistic roll-ups work.

In order to be EVM compatible, Optimism needed to recreate the same environment and context with the same standards as Layer 1. This is what they called the OVM, which stands for Optimistic Virtual Machine.

EVM compatible?

In each virtual machine, there are operation codes, also called opcodes. For example, TIMESTAMP is an opcode that fetches the current time in epoch form.

Let’s take an example of the opcode TIMESTAMP being called on Layer2, and returns a number like 1644784234. Whatever transaction that needed to call this opcode will be stamped with that number.

But, oh no! We just realized that the transaction that Alice made was in a possibly fraudulent block and we need to execute it all on layer 1 to verify it!

What Alice will need to do is recreate the same transaction on Layer 1 to verify that its result is, or isn’t, what the OVM came to. If we call TIMESTAMP on layer 1, it will return something like 1644784234 + 3600, and we definitely don’t want that.

OVM Opcodes

This often happens with certain EVM opcodes that do not behave the same way in L1 as they do in L2. But the Optimism team was the first to develop a solution to this in the context of making an Optimistic roll-up smart contract.

Instead of using {OPCODE}, we use something like ovm{OPCODE}, which modifies the opcode in a way that it completely matches the ones in the Ethereum Virtual Machine, allowing for more seamless fraud-proof verification and for easier access to the state database.

All EVM opcodes that depend on the context they’re used in to function properly have their equivalent OVM opcode in the Optimism smart contract, ExecutionManager.

Certain opcodes aren’t “coherent” with the way the OVM works, and are disallowed by the SafetyChecker contract which makes sure that a contract submitted to the roll-up is OVM compatible.

In a diagram, the Optimistic Virtual Machine Looks something like this:

A diagram of how the optimistic virtual machine works

The question mark is where fraud proofs happen, we’ll dive deeper into that later.

All this is done to allow for the creation of an EVM-compatible context where transactions can be verified and back-and-forth interactions between layers 1 and 2 are easier and smoother.

In other words, a sandboxed environment for the deterministic execution of smart contracts in both L1’s and L2's.

OVM Bytecode

An important problem that needed to be fixed was to make sure that code used in the EVM can be read and processed in the OVM.

This section is out of reach for me to explain in this article, but in very concise words, the OVM team was able to support Solidity and Vyper by modifying their compilers to produce OVM bytecode!

  • The second option would have been to literally make a whole new smart contract language that compiles down to OVM bytecode. Now that idea’s clear and would definitely work, but it would mean redoing everything from scratch and taking a loooooooong time to reinvent the wheel when that’s not how we do things here…

Remember, one of the most attractive features of web3 to developers is plug-and-play. In other words, being able to use other people’s projects and add your own features to them. With the end goal of creating complex infrastructure that has products and projects for every taste.

  • A third option was to transpile EVM bytecode into OVM bytecode, this was tried but eventually abandoned due to its great complexity.

The normal solidity compiler works by turning source code into Yul, then EVM instructions, and eventually into bytecode. The Optimism team changed it so that, after EVM assembly, each opcode would be converted into its correspondent OVM opcode. Or simply throw an error if the opcode doesn’t make sense in the OVM environment.

Geth, the Optimism way

Go-Ethereum is a command-line interface, and it’s the most popular and most used CLI to join the ethereum network. Using geth, you can start a public or private ethereum node on your computer. There are many options to join the Ethereum network using Geth.

Since the Ethereum network consumes a lot of storage on your computer, it makes it really hard for users with relatively simple technology like you and I to join the network without sacrificing a lot of disk space for it. The solution for this is Ethereum light, which is a way to store and run an Ethereum node but without downloading all block data, but just the block headers instead.

Done with the introduction to Geth? Here’s how it works:

On each block, the state processor’s Process is called which calls ApplyTransaction on each transaction. Internally, transactions are converted to messages6, messages get applied on the current state, and the newly produced state is finally stored back in the database.

The OVM Geth works a lot like that too, but with a few changes.

There are 5 major modifications that were made to OVM’s Geth version:

  • Mod 1 — Transactions are turned into OVM Messages and their “to” parameter is replaced by the Sequencer EntryPoint address. This makes it so that they’re processed into a ‘ batch’ of transactions.
  • Mod 2 — As I mentioned earlier, the ExecutionManager contract is in charge of sandboxing all the transactions and making sure they’re all valid. Transactions are internally directed to the ExecutionManager’s address. Where they are passed in as parameters to its RUN function that checks that it’s “OVM compatible” (for lack of better wording). For example, EVM opcodes will be turned into OVM opcodes.
  • Mod 3 — Calls/transactions sent to the State Manager are intercepted during fraud proofs and are either sent to Geth’s StateDB… or not. (the State Manager is a smart contract that is instantiated during fraud-proof verifications but isn’t actually deployed…)
  • Mod 4 Epoch-based batches instead of blocks. Optimistic roll-ups, in Optimism’s case, aren’t actual blockchains. They just keep track of which transactions were made and in what order by using the epoch timing method. This directly affects the concept of block gas limits. Gas consumption is instead rate-limited by using time periods called epochs. After a transaction has been executed, the amount of gas it used up is added to the ‘pool’ of gas used by all transactions in the same epoch. There aren’t block gas limits as I mentioned earlier, but there are epoch gas limits for transactions submitted by the sequencer and Layer1-to-Layer2 transactions.
  • Mod 5 — Now the OVM and EVM are still different machines that can have different states. But the roll-up sync service comes to the rescue by monitoring the Layer1 state and synching the Layer2 state to make sure that the state of the EVM and OVM match and are coherent with one another via Geth’s worker.

Rollin’ It Up

Of course, it wouldn’t be a roll-up if we didn’t ✨roll up✨ all the transaction data. This is the process where data transaction is compressed and put into a batch that is then sent to the Sequencer EntryPoint. The Sequencer EntryPoint is a smart contract that lives on the L2 and is tasked with “rolling up” the transactions into a single group, or batch, then committing it to the Ethereum chain.

Canonical Transaction Chain

There’s a smart contract in Layer1 that is responsible for actually executing this logic, and it’s called Canonical Transaction Chain (CTC). This smart contract represents the official “history”, or chain, of all transactions that have happened in the roll-up. This contract receives transaction batches in two ways:

  • The sequencer (Sequencer EntryPoint), a contract that has priority over other parties that submit information. Its batches often don’t have to wait in a queue.
  • First-in-first-out method where anybody can submit their transaction log. This helps keep the chain censorship-free and allows everyone the chance to participate in the creation and maintenance of the roll-up.

It adds the transactions submitted to it to the history of the roll-up after a certain period of delay. This delay allows anyone to submit something called fraud-proof, which claims that a certain part of the batch is fraudulent. This is how an optimistic roll-up maintains security.

Fraud Proofs

Sidenote: EIP-98

It’s worth noting that fraud proofs are very different from how they were before the Byzantium hard fork. The implementation of EIP-98 meant that there would no longer be an intermediate state root included in transaction receipts. This meant that when a block with an invalid transaction is mined and commited to the chain, it’s impossible to fraud-proof it alone. The fraud proof will have to be executed on the whole block.

Luckily, there are no fraud-proofs in Ethereum natively, since that would be extremely inefficient.

But, so when I said that Optimism doesn’t have any blocks, it was a little white lie, because it has, what we can nickname, “micro-blocks”. This is how Optimism has solved the problem of nonexistent intermediate state roots: by having each transaction be its own block.

Now that we have re-introduced intermediate state roots, we can perform fraud-proofs on single transactions instead of the whole block!

Though this puts slight performance overhead as each transaction contains even more data. But don’t worry, this problem can be solved by replacing all block hashes with ‘0x00' and many other alternative solutions.

State Commitment Chain

The State Commitment Chain (SCC) is the last component to make fraud proofs come together.

It contains a list of state roots which it obtains by Merkle-izing all the intermediate state roots in a batch and saving the Merkle root. The root is later on used in the verification process of a fraud-proof.

A fraud-proof is done by comparing the Merkle root that the SCC provided to the result of applying each transaction in the CTC queue to the previous state of the chain. If the two states don’t match, then the fraud-proof protocol allows for the non-valid state root and all following it to be deleted and replaced with the right state.

The function appendStateBatch is mainly responsible for this process.

RECAP

Now we know that the sequencer does 3 main things:

  1. Receive transactions from L2.
  2. “roll-up” and “batch” the group of transactions together + submit to CTC.
  3. Transform the intermediate state roots into state batch then submit to the SCC.

The not-so-optimistic case

But what if the sequencer is malicious? This is exactly why a waiting period is introduced — in order to allow anyone to submit a fraud-proof.
In simple words, a fraud-proof is this:

“If I start with State-7 and apply Transaction-8 to it, I get State-8, which is not what the sequencer announced. Therefore I am claiming that the sequencer is malicious and am requesting to delete all States starting from, and including, State7.”

Then the process I have mentioned earlier is executed on the batch starting from said state.

The Big Picture

A few more components to make the whole thing come together.

  • A fraud verifier is a smart contract that coordinates the whole fraud-proof and verification process by calling the State Transitioner Factory (explained in the next few lines) and pruning any “batches” that were published after the state root the dispute was called.
  • The State Transitioner is what’s responsible for actually calculating and finding the right state of the chain given a list of root states. The result of its operations is used to compare the current state of the chain to an assumed ‘honest’ state.
  • Lastly, the State Manager is responsible for storing any information given to it relating to the state of the chain that is subject to a dispute, or in other words, fraud-proof.

The OVM

If we were to draw a diagram of what an OVM looks like, it would include all the parts we’ve talked about before and form something like this:

full view of optimistic rollups

Other

Optimistic Roll-ups like Arbitrum and MetisDAO also widely function like this but have a few differences that allow them to present something new to the world of optimistic rollups and web3.

It’s a process that might sound complicated but in the end, just boils down to a few (maybe quite a few) lines of code. But don’t be intimidated to look into this area further and follow your curiosity :)

A few starting resources are this article, this article, and… also this article.

If this article was helpful, stay tuned for the following part of this series, where I will examine zk-Rollups and zk-Snarks/zk-Starks!

I’m basically living on social media, so don’t hesitate to reach out to me on Twitter, connect with me on LinkedIn, and follow my newsletter on Substack!

--

--