FOCIL Breakout #21
FOCIL Breakout · 7 Oct 2025 · 43:42
FOCIL Breakout #21, held on 7 October 2025. FOCIL, or fork-choice enforced inclusion lists under EIP-7805, is a proposal to make it harder for block builders to censor transactions. Lodestar had 6-second slots working with different blobs-per-slot values, and an inclusion list encoding bug was fixed in Reth.
Speakers
Topics
From FOCIL Breakout, hosted by Ethereum Foundation.
Transcript
water. [Music] Thank you. Oh, heat, heat.
[Applause] Heat. Heat. Heat.
Thank you.
Jihoon Song: Okay, thank you. Hello everyone. Welcome
to Fossil Breakout 21st. Today we have a research presentation. Uh Luca from L2 will going to give us a talk about Fossil on native rollups. A native rollup is an EVM based rollup using the execute pre-ompile. So you can minimize the risk of bug governance and so on so forth. For anyone interested, please take a look into this article. Uh let me share it in the chat. After the talk, we can share development updates as usual. So please welcome Luca from Alto Bit. Luca, if you're ready, the stage is yours.
donnoh | L2BEAT: Hey everyone. Uh thank you for inviting me. So I don't have a I don't have slides because I was in uh Singapore last week and didn't have the time. But maybe it's even more interesting this way. So I can maybe share the um uh let me see uh the that website that you shared in the chat. And what I want to do is to let me say is to give you kind of a small introduction on native roll-ups. uh the the idea behind native rollups and why I think that false um is useful is very
useful here uh especially for native rollups but not only so the idea behind native roll-ups is so let's assume first of all that we have uh statelessness on L1 so we can um we can execute transactions we can perform the state transition function L1 without having the full state. So we just have a pre-state route, we have a post state root and we have a list of transactions which are possibly you know stateless uh traces uh to to be able to and now the idea here is if um L1 full nodes can perform a state function which
is stateless in principle they can perform this state transition function on arbitrary states not only the the state of L1 one. Uh so in principle uh these are one full nodes can apply the set position function uh with the state of the roll-ups as well right and if done yeah you know natively uh with reexecution it doesn't bring uh many benefits because you would consume the same resources uh but if we also assume that we have zk on one uh this becomes much more interesting So the idea behind native roll-ups is to
reuse the same stack that is used for Etheum itself but for the for the for the rollups as well. So um the goal of the native develops proposal is to implement a pre-ompile which is called the execute pre-ompile which what it what it does is basically um a recursive function to the state trans function. I have two variants uh in my documents. one that does a um recursive call just to the apply body. Um I assume that you know you are familiar with the with what I'm talking about in the execution layer given that
you know post sale touches this stuff. Um so one variant only does a recursive call to apply body. It skips the header checks. uh while the other variant does uh you know it's uh a recursive call to the state transition function with all the header information. So this is a little bit more um is a little bit longer while the other one is a little bit shorter and the reason why we have both because um a lot of rollups today they skip header checks uh in the first place. So it's interesting to have both.
In any case, the idea here is the execute pre-ompile takes as an input all the information that goes in the block environment uh that is then used uh in the block environment of course and the transactions right so an input is the list of transactions which is ideally a link to a blob or many blobs and then all the information that usually required for this for this block environment. So for example the chain ID this is specific to each rollup this is an input the pre-state this is supposed to be saved in a contract one and you pass it again as an input um you can have arbitrary guest limits
you can have arbitrary coinbase this could be you know a predefined address it could be set to be the same as the L1 Coinbase if you're for example a base rollup And in general, you know, all these values can be inputs and and these inputs are then passed to the apply body which does the actual transition and checks that the transition from a pre-state which is again a state root and a post state is correct using the same execution environment that Ethereum already uses.
And the cool uh like a cool way to read is the same is that the same relation that there is between the consensus layer and the execution layer for Ethereum. uh the same relation can be found between L1 and L2 in the sense of um for example uh the blockcast limit um no sorry like the coinbase is some is an information that comes from uh the consensus layer right uh like all the information that comes from the consensus layer um now comes from L1 from the
perspective of a native rollup Um so another like obvious example is randow right this is something that comes from the consensus layer for native rollups this is an input that comes from L1 and L1 can decide whether to like either pass the things uh from the uh consensus layer as or do something else. Um and this is quite cool because now you kind of have a programmable consensus layer in the form of a smart contracts uh which is which is super interesting.
So this is the like short LDR about native rollups the the important thing about uh this pre-ompile is okay we want to do this recursive call. So that you know the the reason why we want to have this recursive call by the way is twofold. Our first reason is um we want projects to upgrade every time Ethereum upgrades automatically. So if this there is a fork this changes because there is a new instruction a new uh pre-ompile then it is also a new transaction type let's say 772 um they would also be automatically
supported on the native rollups as well. So the these roll-ups wouldn't need to have their own dedicated governance just to be uh just to have feature priority one and the second reason is uh to be bug free because if there is a bug in a native roll up it also means there is a bug on one and it's going to be fixed with a fork. Uh this is not uh what happens today. If there is a bug in a roll up if there's a bug uh then L1 is not going to save them.
So, so we want to do this recursive call, but the thing is the L2 environment is a little bit different compared to L1. Uh, it's not enough to do this uh naively and that's why like there is there are other things uh around not many because again we can say that uh it's it's very we need some some things. So for example, one thing that needs to be supported is messaging uh from L1 to L2. And I have this page that describes um the way that current system works uh like at least popular ones or like most interesting ones or unique like opt implement 12 to messaging
uh which is used for deposits token deposits from L1. You deposit a token on L1, it needs to appear on the L2. And then you need to implement withdrawals uh from L2 to L1, right? So messaging system that for example is able to burn those tokens on L2 and unlock the tokens that are locked in an escro one. And one of those differences from L1 execution environment and the L2 execution environment is force transactions.
So we really want rollups to have the same censorship resistance as L1 as Ethereum. And this means that if for example you have a rollup that has a centralized sequencer and the centralized sequencer is censoring you, you should be able to send your transaction on L1 and have the guarantee that if L1 includes your transaction then also the L2 will process such transaction.
you know I I work at L2PET and one of the most difficult things to implement for a project um is force transactions. Uh they're very complicated. Uh every project kind of has a different way you implement force transactions. For example, if you look at uh opt um they have a new transaction type. uh this transaction type is called a deposited transaction and they need to heavily modify how the derivation works.
Um I can show uh maybe uh like in the derivation if you look at the this is the op uh spec when they draft the transaction list uh like it's quite complicated of course I I will not go into the details uh but they kind of significantly modify the one execution environment to be able to uh support first transaction If you look at arbitum, the way that arbitum implements first transactions, it is even more complicated. Uh they have not one uh new transaction type, but they have uh many
uh this many um and there are projects that try to minimize the um the diff with one. So one example is um Lineia. Lineia is a project that wants uh to be NL2 without touching uh the execution clients at all. Right? And because of this they have been particularly struggling with implementing first transactions because one again doesn't have a concept of first transactions we talked with them for a long time.
They presented us with a doc uh with a proposal for first transactions and basically you know the simpler way you can implement first transactions today in a system is to like with a centralized sequencer is to have some windows uh some periodic windows where anyone can sequence transactions. So basically you have uh these windows where you become a base rollup. Uh Lineia call called them calls this block base blocks. So every now and then uh there can be a base block.
uh which is problematic because if you for a certain period you're based you get into the all the complexity of being based of having base sequencing for preconfirmations and the UX is not great uh in general and we also talked with ATC you know which is this privacy tool and also for them uh it has been like they're not TVM uh but also for them it has been like quite challenging to implement infrastructure mechanism and they also are planning to maybe use this base windows. Um but then in any case the message that I want to send you is implementing for transaction
is very difficult and so if we want to implement for transaction for for native rollup uh what is that we would need to do uh either we we go with this based windows but again the UX is terrible I don't think anyone really would want to uh to do this if they uh if there is another way um the other way is that so the high level idea of for transactions is the sequencer is censoring you. You send a transaction on L1. On L1, you have a smart contract that cues uh these transactions, right?
And then you need to have a mechanism on L1 such that you take the sequencer batches the list of transactions uh that the sequencer wants to post. You take this force transaction Q uh on L1 where anyone can just push transactions to this queue and then you need to have a mechanism to check that the sequencer actually includes the transactions that are in the first transactions right uh so you know this might sound familiar basically the first transaction Q is works as an inclusion
list and you want to force the inclusion list in the uh in the sequencer batches and to do this um it is difficult like most of the time this is done as part of the derivation or like in general this is done as part of uh the state transition this is not a check that is on L1 because checking that some transactions that you have saved to the same storage on L1 are included in a blob because a sequencer or an L2 post stuff in a plot uh probably requires a Z verifier. And the purpose of native rollups is that
no, you know, we want to simplify managing a rollup at a point in which projects do not even need to think about uh ZK verifiers, right? Uh so this is a problem. So I was looking at Fossil and and the cool thing about Fossil is that it implements exactly this mechanism from an execution layer perspective. So I'm you know I'm not looking at the consensus layer at all because it doesn't matter for native rollups in the sense of um the consensus layer um everything that L1 fetches from the consensus layer a native rollup would
fetch from a contract on L1. Um so if you know I looked at the spec again I'm not super familiar but my understanding of the spec is uh there's this new inclusion list that is added to the state transition and then um there is this uh validate inclusion list transactions I think which does exactly uh the thing that first transactions are supposed to do. uh you have the list of transactions that comes from the builder. You have the inclusion list that comes from somewhere else. And then there is this piece of code that checks that the um
that the the transactions that come from the builder includes list transactions. Right? So now um if we have this on one uh all compile would be able to make use of it. So um if we go you know this is the execute pre-ompile uh at some point the execute pre-ompile would do uh state transition call with a blockchain and a block. If we have fossil one here, we would add an inclusion list this inclusion list would come from a smart contract. So again the idea here
uh there is some function that allows user to send transactions on one. These transactions with the full signatures are saved in the smart contracts and uh the um this list is passed as an input to the execute pre-ompile so that the uh state transition of the rollup is conditioned based on these encryption lists. And this would allow to to have to implement post transactions uh without having to worry about a dedicated mechanism to to to check for inclusion.
so I talked about you know checking inclusion in a blob. Uh this is not something that fossil handles today or is supposed to handle. Um but I'm kind of thinking in the future because when um Ethereum will move to ZK the idea here is that L1 itself will also post its transactions uh to blobs. So fossil in a ZK word also kind of needs to check inclusion within blobs. uh this is like a future problem open problem uh whatever but like I'm
assuming uh that L1 will fix for sale with blobs uh by itself eventually and native rollups would be able to use the exact same mechanism uh for for this. So I think I can stop here if anyone has questions.
Jihoon Song: Great. Thank you, Luka. So uh uh you've covered uh what native rollups are challenges of implementing for forced
transactions for rollups with centralized sequencers and how how can we add force transactions to native rollups. Uh if I understood correctly uh I think the main idea is to use the incl transactions field of state transition function to enforce the forced transactions and those will come from a smart contract and any user can send and save transactions to the smart contract whichever they want to enforce. Right.
donnoh | L2BEAT: >> Yes. Yeah, exactly. Uh, so the the thing that I still need to figure out and that maybe uh you guys can help is um how to handle the complexities of sending transactions to a smart contract compared to the man pool, right? Because it could be that you send a transaction to inclusion list. these are used as an input to the state transition but um these transactions don't actually get in because of you know gas limits or or whatever right so there is a problem of like resubmission because uh it could be you know they don't like
we don't have a mele that keeps the transactions these transactions are actually consumed uh so this is kind the complexity that needs to be solved but I'm pretty confident like I'm pretty optimistic that they can be solved also because um existing roll-ups already have this problem uh in a way or the other with with first
Jihoon Song: So as long as we somehow have the transaction included in a block, it's okay, right? As long as the transaction uh has have no problem
um when it's when it interacts with the smart contract like there is no like revert no if that execution goes okay then all we need to care is whether the transaction is included in the block.
donnoh | L2BEAT: >> Yeah. Yeah. Like what I'm worried about is let's say a transaction is at the tip of this queue, right? Uh it is um it is used as an input of this transition uh recursive call like as a an inclusion list but then the transaction is skipped.
Uh I don't remember exactly where uh this is done. Uh like uh where is it here? Right. Uh where is this continue in the spec? >> Uh what happens if if a transaction is skipped? You would need to resubmit the transaction on L1 in this queue.
Uh so
Jihoon Song: yeah the that part is so you can see two continue here uh the first one is to check the if the IL transaction is not a blob transaction because currently we don't support blob transaction >> right
donnoh | L2BEAT: yeah that's fine
Jihoon Song: >> yes you know because of some possible other factor and the second one is uh actually is It checks if the uh not included I transaction could have been appended at the end of the block. So what we want is if an IL transaction is not included then we are executing lines below u 1,110 you know and
donnoh | L2BEAT: >> yep
Jihoon Song: >> if we are hitting that line then we want to see if the IL transaction cannot be appended at the end of a block. So when
we try to validate and uh execute a transaction at the end of a block if we have any kind of a you know exception then that's fine that I transaction is validly omitted.
donnoh | L2BEAT: >> Yep.
Jihoon Song: >> So that's what the code is trying to achieve and ah Right. I guess you're saying that there could be a possible cases that a force transaction can be u validly omitted for some reason.
donnoh | L2BEAT: >> Yeah. Yeah. Exactly. Like what happens in that case >> uh in in a fossil in normal fossil I think it would remain in the mool right and can be uh picked again. I would assume uh in this case you probably would need to resubmit uh your transaction another one.
Jihoon Song: Um I guess it depends if the transaction cannot be included in subsequent blocks for whatever reason then the transaction will be evicted from the mele. Otherwise I think includers will yeah pick it up
again in the next IL just as P said.
donnoh | L2BEAT: >> Yeah. Yeah. Exactly. So like this is kind of the difference that needs to be uh thought a little bit more in the context of native
rollups >> how
donnoh | L2BEAT: to how to handle like resubmission. but again as said I'm pretty optimistic that there is a there is a solution somewhere.
Jihoon Song: >> Do you have a similar cases uh today with forced transactions?
so like the only case um I don't think it there is because so for optimism uh the way the way that in opto works is there is kind of always space for first Um they always allocate some space uh just for them.
So so look you shared uh some challenges that L2s are having to implement force. If we somehow succeed to have fossil in L1 >> like L2s could already implement fossil even without having it on L1 right so um in the sense of like if their goal is just to have a fossil like mechanism they can implement it if their goal is to minimize the D1 which is what most projects want then of course you need to
wait uh for an allord calls this happened many times that someone wanted to something in L1 just to have it on L2 as well. And my feeling is that this is not a strong enough argument for something to be included on L1. But to L2 uh but yeah when we are considering some feature for L1 that we should prioritize L1 over L2. So yeah that's a good point. Um Patus do you want to share something?
Potuz: >> What does it mean fossil on L2? L2 doesn't have four choice. So what part of fossil or
>> Yeah. Yeah. So the idea here is to >> that is an implementation detail. It's not a mechanism simply reusing that part of code in the EL to check that the sequencer batches include for Um it is difficult uh for rollups uh without modifying without heavily or like significantly modifying L1. And the idea here is if the execution already has this check >> uh the roll-ups can
Potuz: reuse this and by the way that the check is going to be
the same. You're you're you're assuming one condition on rollups that rollups are going to
conditions on being includable very different than being includable for L1. It might they might depend on different things >> uh derivation a little bit and um for native rollups we cannot have dedicated transaction types just for first transactions. So how can we implement first transactions uh without new transaction types and without doing crazy things? The simplest thing is to uh like if a one already has a mechanism for first transactions more or less on the execution layer the native rollups that the only thing that they do is a
recursive call to the situation function they would be able to to reuse uh the same exact mechanism and of course this restricts the design space for first transactions a lot that does uh I don't know the the check in a different Okay. Uh but the cool thing about the inclusion list being an input to the execute pre-ompile is that for example you can implement delays, right? So you can pass for examp let's imagine that this inclusion list is a Q1 in a smart contract. you can have a delay of let's say 12 hours or 24 hours before these transactions actually are feeded are actually feeded in the
execute pre-ompile and uh but yes like I agree that this limits the design space uh but native rollups are supposed to be very very similar to to L1's and I don't think you know from a user perspective it makes a lot of a lot difference. Very
Jihoon Song: great. Um maybe we can have one more question if anyone has any.
Otherwise we can move on to the next topic because we have only 20 minutes left. All right, thank you for your presentation, Luka, and thank you for all the Q&A. And if anyone uh pop up with another question, then just feel free to ask him in the chat. Um yeah. So uh for development updates. Um does anyone want to share some updates?
Maybe I can go first. I'm currently adding some unit tests for incology relates to store and then I'm going to share a document that lays out test cases won't be exhaustive from day one so please feel free to contribute um I haven't started it yet but it would be look like this so I'm not sure where to put this I'm I'm going to ask Justin about this maybe placed under faucer for implement repo or consc repo if it's possible not sure yet but yeah that's what I'm working on
at the moment does any client have any development updates
>> but I don't see on the side what's issue
Jihoon Song: >> but you don't see such error when you are working with other features right like we don't have such um error in uh hleski dev net for example so I think
>> yeah there's something wrong with the get prototype I guess so I I rebased it actually last week but I haven't um
which I'm not sure where the issue is there's One uh issue I'm I know about in load that we use the same cutoff for attestation view freeze and proposer cut off but I don't think that matters in a local dev net should be available before the tester cut off anyway
Pelle: >> that should be fixed now though uh there was a bug in just some encoding for the ILS and how we reading it from the engine API but in recent tests I haven't seen any miss blocks from um unsatisfied IS. So um definitely check the newest commit.
Nico Flaig: >> I see. Do you have a image public from if
>> I do not have an image up right
Pelle: to get the metrics working? Um it's there's some issues with like how ref does metrics that I'm looking into right now but we have some basic metrics up and then uh we're also looking
in >> we bumped into the problem that how to count invalid um for example it depends on implementation like they're not invalid so I wonder how other clients implement this u so really count invalid transactions in this case um this new list of transactions like valid and invalid um size bytes gas usage limit um
is it possible to count a bit tricky to count a bit tricky to count invalid transactions u in this case I don't know jihon how uh how it is implemented on the guest side maybe you know it is implemented on the guest side maybe you know or or we may discuss. >> Yeah. So um on the CL side transactions are just byes. So they don't you know uh interpret what the transaction is.
That's why we just care about incology too much. Then yeah we can just decide to not add add new metrics. Uh but on the get end um when so there is a code that checks if there is a leftover enough guest left to add any missing I transaction. So we could use the code to um log whether many metrics and we can you know just trim it out and leave it with all the necessary ones.
Katya Riazantseva: Uh yeah, I don't mind uh any additional transactions just uh I want to be sure that other clients because I think for Pelle he had to change the code to count invalid transactions. So uh maybe he can add as well like um more on this.
>> Yes, Belly.
Pelle: >> Yeah, sorry. I think there was a little bit of a misunderstanding when we were first talking. I I was thinking invalid as in transactions that make the block invalid, not like invalid traction uh transactions because of gas and whatnot. So, it's not really a worry, Ka. Uh but we should be sorry about
that. Yeah.
>> Yeah. Yeah. And I wonder if other >> to other topics.
Katya Riazantseva: >> No, I don't think so. Um it looks it looks quite good. I was think uh I started to build a dashboard like uh CL and DL uh parts separately but now I'm thinking of that it's better to combine for example the metrics regarding payload um it's better to combine them on one panel maybe um and to easily compare CL and E part relate with each other
>> but do you think it's better to >> right so you can see both um EL and CL
for for the similar metrics. Let's say how many transactions sent and how many transactions received. So for these metrics maybe makes sense to to put them together uh whenever it will be finished on the rest side. Um I will share the whole dashboard, the whole picture and we can just
Jihoon Song: yeah we can um continue discussion regarding it. Um, do we have any other updates?
>> All right. Uh quick question about um um same V5 for for fossil or it depends uh if it will be sified for for fossil or it depends uh if it will be sified or >> marge those two changes into one v5 and yeah so if we the bell is already there so uh I think it has priority so if we decide decide to not include in calamster and somehow let's say we want to add it in age fork then we want to
Katya Riazantseva: >> got it thank you
>> y
Jihoon Song: thanks
>> all right otherwise we can go ahead and wrap this call and have another call after after two weeks. All right, then. Thanks for joining and have a great rest of your day and see you guys in two weeks.
Katya Riazantseva: >> Thank you. Bye.
>> Thanks. Bye. >> See you. >> Bye. Bye.
Speaker names adapted from ethereum/pm, CC BY-SA 3.0.