 Let's not work. All right, all right, all right. You just heard Carl talk about a lot of high level things. My talk is, unfortunately, that slides don't look like Carl's talk, so it's a little bit different. I want to ground this, what Carl just talked about, in the actual tech behind the OP stack, right? I want to present to you what the OP stack looks like under the hood. I want to present to you the theory of how you build modular blockchains, right? Not just, oh, let's make some charts, and let's figure it out, and somebody will piece these things together. I want to give concrete APIs and functions that describe the different layers of a system like this. So you can really start to wrap your head around how something like the OP stack works. I'm going to be continuously out of breath because we're 8,000 feet up in the air. It's really hard to talk. Here you go, modular roll-up theory through the lens of the OP stack, a.k.a. You just watched Carl's talk, and now you want to understand how this whole modular roll-up thing actually works. OK, all right, let's go. We're going to do drawings. We always do silly drawings in these talks, so here we go. First, I want to give some context. So I'm going to be talking about the theory behind modular roll-up architecture. The OP stack is a specific software stack that turns this theory into practice. This is about taking that theory and turning into specific software components that you can then use to build modular chains. And I just don't like talking about theory alone. I think theory alone is not very useful unless you ground it. And so I'm going to be using the stack to keep the talk grounded. I'm going to be using the abstractions that we came up with in the OP stack to keep things grounded. I'm also going to use TypeScript Types to represent things. TypeScript is God tier. Don't at me. Here is TypeScript ascending into heaven because truly greatest language of all time. I hope you enjoy it. Let's go. All right, so modular roll-ups 101, which I lost the mic. Oh, there we go. I'm going to get it back. Give some brief history. Back in 2020, everyone was building monolithic roll-ups. This is what they looked like, beefcake roll-ups. Really absolutely ripped six-pack roll-ups. It was one giant code base. And it was really hard to understand where the separations were and what did data availability mean. Basically, everything was defined and limited by our proof systems. So we were like, OK, what is a roll-up? Well, an optimistic roll-up, we have to build this fault-proof. So we're going to build the fault-proof. And then we're going to figure out how to make this system work like the EVM inside of a functioning fault-proof. And we did that because we had no clue what we were actually doing. We had no clue what roll-ups really were. This was us. How do we roll up? Who knows? Let's just build something. Oh, yeah, that's what we did. Mental models are really, really important. If you don't know what you're building, you're going to build it wrong. As an aside, I think this is funny. I've been working on this stuff probably for five years now. And every six months, we sit there and we're like, ah, it actually works completely differently from how we thought it worked. The other day, Carl and I are sitting there and we're oh, withdrawals are just totally not what we thought withdrawals are. So it's crazy. It's just interesting. I think we really don't understand the problems that we're working on. It takes a long time for us to build those mental models. And so if you don't understand something, that's OK, because not everybody does. Nobody really understands what they're working on, even when you're working on it and building a whole protocol out of it. Then we finally got it. So between 2021, 2022, we started to really understand roll-ups in more detail. The first key realization was that proofs should be separated from execution. We should not allow the structure of the proof to control the behavior of our execution layer. And this was, so here we go, with the power of mental models, I vinquished the monolithic roll-ups. Oh, Jesus, oh, they got ripped in half. Oh, no. And so then we got stuff like optimisms, EVM equivalence upgrade, arbitromes, nitro upgrade, all the same idea. Let's separate proofs. Let's just run the EVM as built with minimal modifications to make it work like a roll-up and have the proofs be so general that it doesn't matter what you do on the execution layer, you can do whatever you want. All right, then we also came to realize that we could break out the data availability layer. Bra, right? So we got a fork and it added it to the Data Availability Committee. Arbitrum releases NOVA with the Data Availability Committee. This is all a realization that we can also separate data availability, right? We can include a different thing that's not Ethereum and these systems can still work with different security properties. And so roll-ups were coming modular, right? We start to see this. We generally start to see roll-ups beginning to break down into three primary layers if you've looked at modular roll-ups before because people have been screaming about this for the last year. You kind of understand where it's going, consensus, execution, settlement. That's the high level idea. But that's the high level, right? Isn't that just modular blockchains? Yeah, in a way. But really, it's about taking the theory of modular blockchains and putting it into practice. It's about saying, OK, let's not just have charts in a blog post that says, well, if you separate it, if you put this, it could be this thing. And if you put this, it could be a Volidium and whatever. But actually saying, let's define a software staff that makes it possible to put the things together for the average person to not have to build the whole thing from scratch. And it was time to make things official. So this was modular blockchain design and being put into practice. But at the beginning, it was very messy and very haphazard. People were kind of just ripping things out. They were kind of just tweaking the execution layer and hoping that it worked. There wasn't any formality around it. So you know what time it is. It's formalization time, like loosely formalized because I never graduated college. So I don't know how to do that. But it's good enough. It's good enough. All right, so here, section two. Now, the section numbers are completely messed up. I just never got around to fixing it, but whatever. Beep boop bias warning. I'm going to use the abstractions that we define in the OP stack. I think these abstractions are good. There are other abstractions out there. But I think the OP stack's abstractions are pretty good. So deal with it. I'm going to use those. Like I said, there are three primary layers. We've got consensus. Inside of consensus, we've got two things. What we call data availability. You've heard of that before. Derivation, you may not have heard of that before. Then execution, then settlement. So let's look at consensus. Let's specifically look at these two subcomponents. We've got the data availability layer. And we've got the derivation layer, right? So what is the data availability layer even? All right, let's try to formalize this a little bit. Well, you know, it's like the place reposed data, right? Like how does that actually work? So let's get slightly more formal. I like to say, and I think a good way to think of the data availability layer is it's an ordered list of blobs. It's just an array of byte strings, right? That's the most abstract way that you can think of the data availability layer. There are certain properties that you might want out of a data availability layer in practice, right? You really want this to be a mostly immutable, append-only list. You want this, the data, to actually be available. But that's an implementation detail of the data availability layer itself. At the highest level, it really just looks like this. It's an array of byte strings. In the context of Ethereum, right, if we look at this, what is that array of byte strings? It's pretty straightforward. It's just every new block. Every block is our blob, right? And it's this array of blocks that just grows and grows and grows and has pretty good data availability properties and has pretty good immutability properties. So you can do that. Here's whatever some code of we're pulling the data from L1 blocks. Those are our blobs. Same idea in 4844, except you're looking at the 4844 data sidecar instead of looking at the primary block. You've got stuff like Celestia, and you've got a stack of post-its. You could do it with a stack of post-its if it's a sufficiently good stack of post-its. All right. So array of blobs, pretty straightforward. Generally, blobs blocks. Now let's get into derivation, because derivation is what I think to be one of the more interesting layers in this whole system. At a high level, derivation is taking the data availability layer. And it's understanding what that data means, and it's parsing it. And using that data plus the current state of your Layer 2 system, it's producing the inputs to your chain, right? It's producing, for example, I'll get to it, but it can produce transactions. That's sort of the classic example. In our case, we use the Engine API. The OP stack uses the Engine API. Why the Engine API? Yeah, it's like one of these things we're opinionated on, basically. We think, as optimism, we're building this EVM equivalent optimistic rollup. The Ethereum already standardized the separation between the consensus client and the execution client. It didn't really make much sense to come up with a totally new way of driving execution. You might as well just reuse the same thing because the APIs are there. All right, let's go. So let's formalize this. What does this actually mean? I think this has a relatively simple function signature, and it kind of looks like this. You have this derivation function, and it takes the previous state of your rollup, or your system. It takes the data availability layer, and it's either going to produce a payload for you to execute on the execution layer, or it's going to produce nothing. And it might produce nothing if, let's say, you're a rollup, and there just haven't been any new transactions published to Layer 1. It might just say, well, I looked at this new block that came in from the data availability layer, and there's nothing new to put into the rollup. So I'm just going to produce nothing. Or it could look at a block in the data availability layer, or a blob, whatever, and it could say, OK, actually, here there's a transaction that we need to execute on our Layer 2 system. So let's make this a little more concrete. Let's look at derivation in bedrock. We look at data from three locations. The number one piece, like the most common place we look for data, is sequencer data posted to a specific address on Layer 1. This kind of makes sense. The sequencer collects a bunch of user transactions, compresses it, shoves it onto Layer 1, and it posts it onto a specific address. Not a contract, interestingly enough. And it's actually very complicated if you want to derive this and make it extraordinarily efficient. So it's in multiple files here. But you could make this much simpler if you really wanted to at the expense of gas costs. Then we derive data from a second location, which is deposits sent to the portal contract, which is basically our deposit contract. So when there's a deposit event emitted by the portal contract in a block, we're going to derive a Layer 2 deposit transaction. Here's how we do that, right, whatever. Then the Layer 1 block data itself, every time there's a new Layer 1 block, we're going to derive a special transaction on Layer 2 that carries the information about that Layer 1 block into the Layer 2 state. Here's how we do that, whatever. The point is that we can transform all of these different data sources into payloads that get executed on Layer 2. And this abstraction is actually really, really powerful, and I want to hammer this in. Because if you want to build a roll-up, you do what we just talked about. You read sequence transactions, read deposit data, read block data, whatever. But that's not the only thing you can do with this. You can derive data from almost any piece of information that lives on Ethereum or lives on your Data Availability Layer. So I want to just show you a toy example of something that I think is really cool that you can do with this. Let's say that you had a Layer 2 without user transactions, without anything. And the only way that you derived these engine payloads was every time there was a Uniswap swap event on Layer 1, you derive a transaction on Layer 2 that includes the assets and the amounts. And you feed that transaction into a smart contract on Layer 2 that keeps a running tally of the volumes. That kind of looks like something. Like all of a sudden you have this thing, this provable thing that is deriving data from Layer 1 and is generating some sort of state on Layer 2. And it kind of looks like an indexer. You can essentially build an entire verifiable indexer as a roll-up. Are they just roll-ups? Who knows? I think indexers are kind of just roll-ups. People just didn't realize it. There's a lot you can do with this. You can derive Layer 2 payloads from anything on Layer 1 and you can do so much with that. All right, Section 4. See, it skipped Section 3. This is whatever, Section 3, 4. What is the execution layer? Let's get on to it. It is what you think it is. The execution is what you think it is. It's the interesting part of the state transition function. It's the fun stuff. It's where you get to do your crazy applications. Of course, in this system, it's also represented as a function in a very abstract way. It looks like this. You take the previous state of your system, you take a payload that was derived by the derivation layer, and you're going to transition your state into the next state. This is very abstract. In this statement, it says nothing about the EVM. It says nothing about the actual state transition function. It just says you need a state transition function. Derivation and execution in this system work together. They work together to form something that I call the state transition function loop. The loop is very simple. When there's a new element that comes in from the data availability layer, so let's say a new block was produced on Ethereum, we're going to pass that into the derivation function. And the derivation function is going to do one of two things. Either the derivation function looks at that block and it says, eh, there's nothing in here. There's nothing to put into the Layer 2 system. There's no payloads to derive. No transactions were published to the special sequence or address, whatever. And in that case, it's just going to wait for the next element to come from the data availability layer to look for the next thing that it might derive. Then the other option it has is to return a payload. If it returns a payload, it's going to pass that payload into the execution function where the state is going to get updated. Then we're going to go back to the derivation function to see if there's anything new to derive. And this thing just repeats and repeats and repeats and this is your entire transition function. If you want to see that as a little drawn out image, essentially, we have the data availability layer, a new blob comes in, we derive something. Is it null? Then let's just wait for the next thing to come in. If it's not null, then we're going to derive a payload and then we have to execute that payload, see if we derive anything new and it goes in this beautiful figure eight for all of time, right? This is how derivation and execution work together to form the state transition function loop. All right, execution in bedrock. Let's make this a little more concrete. How does this apply to what optimism is doing? In optimism, it's just the EVM. We just changed the EVM. Mostly it's just the EVM. We added a few things that you need to do to make a system roll up compatible. The primary diff in our diff is the addition of a new transaction type called a deposit transaction type which allows contracts on layer one to interact with layer two, right? It's what allows you to perform deposits. It's essentially the message passing layer. You need this in the EVM right now. I don't know that we know of a way to do it without adding this diff, but it's a very, very, very small diff. And essentially we're now at less than 1,000 lines of code in a single commit. Here's the diff like Carl showed and actually 71 of those lines are this circle CI config file, so it's 750. This gives you a really important thing because it gives you support from multiple clients. It means that we can very easily port our diff to multiple clients. And if you don't have multiple clients running, a bug in a single client can be catastrophic for your rollup no matter how good the proofs are because the proofs are just confirming the execution of your clients. If the proofs are just confirming the execution of your clients and there's a bug in your client, then the proof is gonna say go ahead, the bug executed correctly and nothing matters. So you need client diversity and having this small diff is a critical part of that. If you want, I don't know if people can scan this, should scan, this is the diff. Or you can go on our GitHub repo, OPGeth, and you can find it's a single commit which makes it extremely easy to rebase onto the latest head state of Ethereum, or of Go Ethereum, makes it super easy to deal with. So all right, let's continue because I don't have a lot of time left. Just because we're doing the EVM doesn't mean you have to do the EVM. This approach is really, really flexible. There's nothing in this that says you have to do the EVM. You can do whatever you want. You can annoy the Maxis and do a Bitcoin roll-up. You can put a Game Boy inside of a roll-up. You can do a Python interpreter inside of a roll-up. As long as you have a state transition function, you can put it behind the Engine API and the rest of the system will just work. Publishing transactions to Ethereum will just work. The fault-proof system will just work. Everything just works, you just switch it out as long as it compiles to MIPS. You're good. You're fine. So like Carl said, the sky's the limit. You have so much flexibility with this design and I highly recommend that you mess around with it. Ooh, okay. Onto the really final part of this talk, settlement. Settlement is kind of the fakest part of all of this. It's a little hard to understand. Is it even a real thing? And I think, yeah, in a way, this is how I'll define it for the sake of the OPSE tab. Settlement is a view that another chain has your chain and it's about making claims about the state of your chain to another chain and being able to back those claims up. And so if you think about that for a second, that means that you can settle to multiple chains at the same time. There's nothing about this definition that says you can't settle to Ethereum and Bitcoin at the same time. There's nothing about this claim that says you can't have multiple settlement layers, settlement mechanisms to the same chain, right? Because you could be making claims and you could be backing those claims up in different ways. Essentially, it's just about making claims and backing them up. And actually, let me get to that in a second. Well, we'll see, whatever, fine. All right, so you can make all sorts of claims about a system, but the one that you'll find most commonly is making a claim about what we call the state root of the system. The state root in Ethereum, you kind of, if you've played around with Ethereum before, you're probably familiar with it, basically it's just a commitment to everything, right? The full state of Ethereum. So similarly, generally, the easiest thing to do is just to make a claim about a commitment that commits to everything. And then when you make that claim about the commitment that commits to everything else, you can just prove against that commitment and now all of a sudden you can do pretty much whatever you want. But that doesn't mean that's the only way to do commitments. You could do commitments about specific claims on layer two. Like this very specific thing happened on layer two. It's just that the most general and generally the easiest thing to do is to make a claim about the state root. In order to make a claim about the state root, we need a function that looks like this. It's this validity function. This looks very straightforward. We have a previous state. We have the next state that we're trying to figure out if that next state is valid given the previous state. We have the data availability layer. We have the derivation function. We have the execution function. All stuff that we've already talked about and we spit out a boolean, right? We spit out something that says is this state transition valid? And so the key question of how do you actually make this work in practice, right? This sounds great but how does this work in practice? So look at this carefully. Let's try to figure out where each one of these inputs comes from on chain. Let's say we're settling to Ethereum. Where does this come from? So state is a given. The previous state, we agree on the previous state. Generally, that's how we wanna design these systems. We start with the previous state that we agree on and then we have a next state and even if we don't agree on the validity of the next state, we generally agree on the fact that this is the thing that we're putting into the function. So the first two are givens. The derivation function and the execution function are literally functions, right? They are pieces of code that run and you could implement those things on chain. The old OVM, Optimism's old architecture, implemented those things literally on chain so you execute the entire function on chain. Generally speaking, that's not feasible depending on how complex your system is. So we tend to bypass this and instead of implementing the functions on chain, we basically implement something that acts like a proxy of the function and that's usually either fault proofs or validity proofs, right? These are our proxies for the execution because it's too expensive to actually carry out the execution on chain. But you can think about how this fault proof or this validity proof is representing the derivation in their execution functions. It is the code of those functions. It's just that we execute it in a different way. We execute it in a way that is actually feasible to do on chain. But the interesting question is how do we access the data availability layer, right? How do we get access to that data availability layer on the chain that we're settling on? Of course it's another function. If you remember our data availability layer it takes the form of this array of blobs. So we want a function to access this data availability layer and kind of an easy way to do this is you have this thing that says get blob by index, right? If it's an array and you have like get blob by index, you can access any element, right? But there's something really important being formalized in this idea. And the important thing is that there's two properties that this function kind of encodes under the hood. The first property is that the ability to resolve this function, the ability to actually return a blob by a given index is fully dependent on actual availability of data on the data availability layer. If the data's not available, how are you gonna return something out of this function? You just can't. The second thing is that you have to depend on a mechanism to prove that the blobs are correct. Because otherwise I can just give you anything, right? And I can just say, oh, the data was ABC, but it was really something completely different. So you need a proof mechanism. Let's see if we, okay, let me go to this really quickly, go back for a second. Okay, so in Ethereum, you know, the proof mechanism will get to that in a second, but for something like, let's say, Celestia. Celestia's data lives on a chain other than Ethereum. And so what we need, if we wanna prove that a given piece of data is correct, we need to first carry over commitments to Celestia on Ethereum, and then we need to prove against those commitments. So now we're essentially relying on the, not only are we relying on the availability of the data availability layer, we're also relying on the correctness of the function, essentially the like client, that is carrying commitments to Celestia onto Ethereum. And there's two things that you need to think about when you wanna use something like Celestia as your data availability layer. All right, so let's just look quickly about how Bedrock sort of does this validation. In Bedrock, we start with the latest block. This is the magic, right? Ethereum has this beautiful thing that Ethereum, from the latest block, you can access everything. It's beautiful. The block hash, hidden inside of the latest block hash is all of the information about Ethereum for all of time because I can start with the latest block hash and then I can reveal the block and I can reveal the previous block hash and I can reveal the previous block hash for that and I can just go back in time to infinity and I can access every single block, an entire history of Ethereum and not just every single block, I can pull out every single piece of data in every single block in Ethereum. And so what I'm gonna do in my validation function is I'm gonna start with the latest block and all of this is kind of hidden inside of the fault proof but my program is gonna walk backwards and walk backwards and walk backwards and figure out which blob in the data availability layer, in this case, Ethereum blocks, it's going to start the state transition function loop from, that's the loop that we just saw and it's gonna apply that loop over and over and over again in the program until you get a final state and you compare that final state to the final state that you proposed. And all of this happens inside of the fault proof so none of this computation really happens on chain. You just sort of have to, if you wanna challenge it, you just have to do a single step but this is the magic of Ethereum which is that the data is guaranteed to be available and the data is guaranteed to be correct because you're settling and putting data onto the same place. All right, so bringing it all back together really quickly with the multi-headed angel thing going on here. There's a lot of content but there's not that many components to something like this. Remembering the components, we've got the data availability layer which this is ray of bytes, ray of blobs. We've got the derivation function which takes the previous state and the data availability layer and it's either gonna spit out a payload or it's gonna spit out nothing. You've got the execution function which takes the previous state and it's gonna take in a payload generated by the derivation function. It's gonna produce a new state and you've got this validity function and then inside of this validity function you have this get blob by index, right? So this is, all of this composes each one of these different layers is an API that you can plug into. So you can take this and you can build your dream chain. If this isn't just theory, this is in the Optimism's code base, in the Bedrock code base, you can build whatever you want. Do you wanna build a Bitcoin plasma? Yeah, you can build a Bitcoin plasma. You can do it really easily. Go build a Bitcoin plasma. You wanna build a bridge that's actually a rollup and it has multiple data availability layers and multiple settlement layers. Why not? You wanna build another paralyzed VM and raise like $200 million from VCs. Why not? You can do that. You can build whatever you want. You just have to fit the APIs, right? That's what we've, we've boiled this all down to a set of APIs. If you fill the APIs, you can build it. So that's the whole talk. Thank you. Try to remember life. My name is Kelvin. I'm building the Optimism Collective. Bedrock specs. Get in touch. Thank you. Build something cool.