 Our next speaker is Sergio Mena. Sergio obtained a PhD in distributed systems from EPFL as well. And before that, he was also at EPFL, which seems to be a recurring theme so far, and at the Technical University of Valencia. He worked as a teaching fellow at the University of York and as a software engineer at Cisco, where he worked on congestion control algorithms. Currently, he's a research engineer at informal systems. His research interests include fault-tolerant distributed systems and congestion control for real-time media. His talk today is titled ABCI++, Evolving Tendermint Modularity, and in this talk, he'll be discussing the Tendermint Application Blockchain Interface, its limitations, and the next steps in its evolution. Sergio, you're up. Thank you very much for your interaction. Let me start by sharing the screen. Good day, everyone. My name is Sergio, and today I'm going to talk about consensus, not surprisingly, Tendermint and its modularity, in particular the interface and the major evolution that it is undertaking. This is the outline of my talk. I'll start touching on the context of the work we were doing here. Then I will focus on the problem to solve, so the justification for ABCI++, which is the main focus of my talk. Then we will get into the details of ABCI++ and what can go wrong there to then discuss how to properly use ABCI++ so that nothing goes wrong. And then I will conclude my talk. So without further ado, let's get into the context. So from a corporate context, I work for informal systems. At informal systems, we aim at verifiable systems for organizations. So on the systems front, we are a core contributor to the Cosmos ecosystem. We have dedicated teams in Tendermint and IBC and recently also on the SDK. But we don't stop there. We also take the extra mile to do formal verification. So we build TLA++ models of the specs that then we can model check with tools such as Apalachee. And on another front, we also use model-based testing techniques to make sure that our TLA++ specifications do match the implementations that exist. On the organization side, we are a co-op, so a cooperative, which is owned by the worker members and we are working on new ways to interact, to organize ourselves in order to maximize the employee well-being. So far for the corporate context, now let's get a little bit on to the technical context. So this slide is state machine replication at work. Tendermint stacks. So each of the circles that you see here is a node in the network that is running our replicated application. If we zoom into one of these circles, we can see there are several modules. So the green one, which is Tendermint, the consensus module, then there is the blue one, which is the application, the replicated application, the state machine, and they talk to each other via this yellow arrow. The rest of this talk is focusing on this small yellow arrow. So let's now focus on the problem that we are trying to solve. So the justification for the work that I am presenting here. So in the distributed systems literature, usually we represent the modules in this way. So we have a consensus module, which offers the properties that everybody knows. And then there is the application, the state machine, the replicated state machine. And we have this propose v and decide v primitives. So whenever the state machine is ready to propose a new value, in blockchain is going to be a block, it calls this primitive on consensus. Then consensus does its magic via the network or whatever it is. It follows basically its algorithm. And when it is ready to decide, it's basically calling this primitive onto the application to say, hey, this is the decision that has been taken at all nodes. Again, v in the concept of blockchain is going to be a block. Now, this is the theoretical explanation. Now, how was this implemented? How was this realized in the Tendermint stack? So in the Tendermint stack, this looks like this. I have this is just a simplified version. There are some APIs that I've left outside this presentation for the sake of simplicity. But basically, we see that there is a slightly different way of doing proposals and also kind of a more complex way of doing this side. One important thing that I would like to make clear at this point is that in ABCI, so this is the interface we call ABCI in Tendermint, that the consensus is always the client and the state machine is always the server. It doesn't mean that there is a network between them. Usually, there is none. They are collocating in the same machine, but even in the same process sometimes. But consensus is always initiating any interaction to which the state machine reacts. So the state machine does not have the right to initiate any interaction. It's always consensus that has this initiative. This is something important in ABCI that we have kept in ABCI++. So it's very important to understand in order to better follow the presentation. Okay, so we have our nice ABCI system. This has been out for years now. This is what's out there on the field. And so what is it that we need to solve here? Because the solution is already there. So several things to say here, several observations. So the problem tends to be on what applications do, can do, and what control they have of the particular of the proposals, but not only, okay? So applications do not have control over a proposed value. So as you can see here, well, there is this new module here called Mempool. This is an idea taking from Bitcoin and Ethereum, whereby you have this small module that gossips the outstanding transactions and it's also used as the basis for proposing blocks. So in the ABCI status, in the ABCI implementation, we have that consensus is always proposing the value and doesn't count on the application for anything. So there's no control by the app on the proposed value. And so that means that we cannot filter invalid transactions. Since this is a modular design, the transactions that are in here can only be understood at the level of the application. Consensus considers transactions as opaque entities. And so if there is an invalid one here, there's no way consensus can detect it. If we take this argument to the extreme, then there is no defense against Byzantine proposals. So in tandem, there is always like one of the nodes that is the one that we're proposing the value at each time. So if that one is Byzantine, you can imagine this node proposing a massive block full of garbage transactions. There's no way today to explicitly filter this in ABCI. And so what is worse, as we all know, by the rules of state machine replication, all decided blocks have to be reacted to in a deterministic way. And we all know that these garbage transactions I'm talking about are some sort of like fuzzy transactions. So reacting deterministically to fuzzy input is one of the most difficult things you can do in distributed systems. So this is, the deterministic requirement there is also a pain point in terms of the burden that is put upon the application designer and implementer. And another thing, an important thing that we will come back to during the presentation that we want to tackle is the mempool front running. So there are more subtle ways of being Byzantine, not just fully Byzantine, but you could actually imagine a node that is just behaving apparently correctly, but it's just in front running, it's introducing its own transaction in its own proposals that is seeking to have some sort of unfair profit at the application level. And we don't have like a very good way of tackling this problem in ABCI. Now less important, but also worth mentioning is the implementation of the side. Remember my previous slide in academia, we tend to call this the side. So the API for the side is suboptimal because the transactions are delivered with this delivery X, so one transaction per call, they are delivered sequentially. And I'm gonna touch on this in a few minutes. So this is a summary of the main problems that have, say, appeared over the years when using ABCI. And these are the main motivations for us to undertake the work that we are presenting in this presentation, which is called ABCI plus plus, which is kind of a code name of the next generation ABCI. So in the next slides, what I'm going to do is I'm going to zoom on different parts of this API to explain, bit by bit, the changes that we have introduced in the API. So let's start by the end, by the decide API, this is the simplest to explain. As you have seen, there is this sequence of APIs, begin block, then labor takes zero or more times and block and commit. This has now been transformed into finalized block and commit. So what has happened here is that we have coalesced all these calls into one single one that is delivering the whole block in one shot. So what are the advantages here? Well, the application now can be made more efficient because if the plot contains orthogonal transactions, those transactions might now be executed in parallel because they arrived at the application at the same time. More generally, you can actually make more flexible the way you transition your state machine. So you don't have to follow the strict order as long as you are deterministic, as long as every node does the same. And so there is more flexibility here in how to transition your state when you receive the block. And one small detail, as you can see, the commit is not coalesced into finalized block, it's still a separate call. The reason for this is because commit is crucial for our current cross recovery mechanism. Commit is basically signaling the application now you have to persist your state. We are planning to revisit our cross recovery mechanism. This is something we didn't do at this time, but once we've revisited, chances are that we will be able to finally also coalesce commit into finalized block. Okay, so this is the thing that was worth mentioning on the decide part. Let's now move on to the proposed part. So as you could see in ABCI, this was the proposed part, the most obvious characteristic here, the most obvious element is that the state machine is not involved in the proposal. So we have introduced a new API called prepareProposal. It works as follows. Whenever consensus is considered, it's time to propose a new block, as just as before, it will reap the transactions from the mempool. But then at this point, it will actually make that row proposal available to the state machine via this API. So now the state machine has control over proposals. It can do things like adding transactions, removing transactions, because it realizes they are invalid. It could even reorder transactions so that all transactions, or as many transactions as possible are valid, et cetera. It has a certain degree of control on the proposal and it can modify the proposal according to application dependent rules. It can, it doesn't have to, but it can also execute the proposal once it has prepared it. It can execute it at this point rather than at decision time. This is what we call immediate execution. What is to be gained with doing that? So if you do that, you have a full guarantee that all transactions that you are including in the block will be valid because you are executing them at the same order. They're gonna be appearing at decision time, in the case this is the block that is finally decided for this site. And these with little performance cost because all the energy that you are, that you are expending into fully executing the block will be able to be, you will be able to reuse it at the decision time in the case this is the finally the block that is decided, which we know that in, like it's kind of the happy path. So it's, this is what is gonna happening most of the time because the network is gonna be behaving in a synchronous way. Good, and then there is a second part of proposal which is of the proposal part of the APA which is process proposal. So whenever a proposal is received by consensus before in ABCI, it was just dealt with internally according to the algorithm. Now we are exposing that proposal to the state machine so that the state machine can actually tell consensus to reject a proposal. If it deems that what is inside the transactions is not a valid one. So the guarantee we offer to the application is that they tell us to reject that proposal, this proposal will never make it to decision and other proposal will be decided. So the validity check that used to exist at consensus level is now extended also to the application level. So that's why we call this external validity. These allows us very obviously to filter against Byzantine proposals. So if you think of the example I was describing before of a Byzantine node that has this massive block full of garbage transactions. This is probably very easy for the state machine to glean that, to detect that and just say, no, this proposal is invalid, please don't decide it. Let's not waste any time on trying to process this block. And just as a prepare proposal, when the proposal is made available to the state machine you can actually execute it at that point as though it had already been decided. So this is very similar to prepare proposal and this is actually allowing us to improve this validity check to make sure that no transaction is invalid. Now, very important here, tendermint is so the consensus is now rejecting proposals that used to be accepting. It is rejecting proposals based on logic that is not in the algorithm. So this has liveness implications. There are things that are now rejected that didn't used to be. So we're gonna get back in the second part of this presentation, but this is very important to us. So let's continue in the consensus. There is many consensus algorithms in particular in tendermint, there is a voting phase. And ABCID's voting phase was totally managed in an opaque way with respect to the state machine. The state machine had no say on that. We have changed that in ABCID++ to introduce this new API extend vote. What happens now is that when consensus is about to send a vote to the network, it is going to make, to ask the application to extend that vote. So the application is gonna provide some opaque data, a byte array, which we call vote extension that then consensus will sign and attach to the message. And this is the final message that is hitting the wire. Now, very important, the data that is inside this extension is not covered by agreement of consensus. Very obviously this extension appears very late in the game to be able to be covered by agreement. So anything that is happening after the proposal is sent is circulated, cannot pretend to get protected by agreement. So this is very important. The property that we are after here is not agreement is something weaker. The property we are after is that a majority of votes at the end of a consensus height, let's say at the end of height, there's gonna be a majority of votes that each with its corresponding verified extensions that will be very useful for something to the application that we will see later. Okay, in the particular case of tendermint, a majority means a super majority, so more than two thirds worth of voting power. And what I mean by verified is then the subject of the next slide, which is the second part of the API. Before again, remember, there was nothing when a message is received, nothing happened at the application level. Now we have introduced this verifiable extension, whereby we take the extension that we receive from another node, for instance, and we're gonna have the state machine tell us whether this extension makes sense or not. So now the state machine can tell consensus to reject certain votes if the extension is not valid. An important design decision we made here is that even if the vote validates at the consensus level, if the extension does not, we're throwing away everything. It's an all or nothing policy. This allows us actually to filter against the visiting voters. So basically when this says reject, that's evidence that somebody is trying to fool the system by behaving in a visiting way. And once again, tendermint is now rejecting votes that it used not to reject, based on some application logic. So it is slightly modifying the consensus algorithm in a way. And so there are lightness implications here as well. So we're coming back in the second part of the end to talk. So this is the whole tour of the new API. In this slide, what I'm doing is just summarizing what I have presented in the previous four or five slides. So we have this traditional ABCI way of organizing things in the tendermint stack. That became this where we introduced prepare and process proposal at proposal time, we have extend vote and verify our extension that didn't exist before either at the voting phase. And then we have simplified the side primitive into only two API calls where all the block is delivered to the application in one shot. Now, as there are new ways for the application to interact with consensus, these new ways are open to applications misuse. The applications could be misusing this. We could see, we have briefly touched on like some lightness implications. So these abuses from the app can put consensus properties at risk. And what is worse is that then you would have to start reasoning about this as a whole. And so you would be defeating modularity. If you need to, in order to prove consensus properties, you need to get into the detail of the applications, we are actually not being modular. And this would be a problem. So the application must behave, but we need to somehow come up with a way to tell the application how to behave without having to explain the whole consensus algorithm. Application developers or application designers are not interested in consensus details. They are only interested in their application being replicated, that's it. And then of course the many things they have to worry about the logic of their application. The applications that we tend to put here in academy are very simple, but the ones that are implemented in this industry are really complicated. So they have many things to worry about other than what consensus properties they might or might not be respecting. And so this is the subject of my next, of the next section of the talk, which is what can go wrong in ABCI++. So in the specification, this is the link to the specification, we have come up with a set of comprehensive set of formal requirements to the application. So things that the application's behavior has to abide by. And if the application respects those requirements which are expressed in a formal way, so no details about how consensus behaves, then the application is safe and can count on consensus properties. Here there are two examples, the two examples I wanted to share with you, they are non-exhaustive, but they are very interesting. The first one, let me just explain it briefly is that if you have two nodes that receive a block, a proposal, and they execute process proposal, they have to be deterministic. Either both of them accept them or both of them reject them. Actually, both of them is a formal way of saying everybody, everybody that is correct, of course. That's the determinism. You cannot have a situation where you get a proposal and half of your nodes are accepting them and half of your nodes are rejecting them. I think people that understand consensus can clearly see that that's looking for trouble. And then we can actually go further in this coherence property where we have like, if I am correct and I am preparing a proposal, I'm putting a set of transactions that I'm actually making available to other nodes and I am correct, then everybody that is correct must accept my proposal. In other words, the implementation of prepare proposal has to be coherent with the implementation of process proposal. Proposal proposal is only allowed to reject values if it has evidence that these values, these blocks, are the result of a Byzantine behavior. Now, for instance, for extent vote and verifiable extensions, we have also similar determinism and coherence. I'm not gonna get into it because it's very similar to what I just explained. You want to, again, you want to see the full list of properties we came up with. Here's the specification. This is all you need to understand in order to build your application. You don't need to, this doesn't, in order to understand these properties, you don't need to understand how consensus works. And this is basically our way to guarantee the properties at consensus level whilst keeping the application modular in the sense that the application doesn't need to reason in terms of consensus. Okay, so now that we deliver the bad news, let's get into the good news. So what new cool things can we do with ABCA++ which was either impossible or very cumbersome in the past? So let's start by prepare proposal and process proposal. So a proposal time, some of the use cases. So we have touched on some of these already. So you can reorder some sections. So the obvious use case here is like applications that have transactions with sequence numbers where, for instance, you cannot have gaps, et cetera. So there at prepare proposal, you can actually reorder your transactions or delay some transactions if there is a gap so that these transactions never fail. This is something we cannot do with ABCI. Transaction aggregation, maybe to make the, if possible to make the block more, like to optimize the space of the block. Transaction, you can go to the extreme, like with transactions reorg. For instance, the Celestia project in Cosmos, they're doing something like that, like they're taking every transaction, split it in half, and the information of each transaction is basically being reorganized in different transactions. So basically they limited your imagination as to what you can do there. We can deal with the visiting proposals, as I already mentioned, particular with process proposal that is now able to look into the transaction content and deciding whether the proposal itself should be accepted or rejected. And we have immediate execution where basically you execute your block at the moment it is proposed. And therefore you have 100% guarantees that all transactions that are in that block are gonna be valid in the case it is decided. And all that with a small performance penalty, as I already explained. Good, so then before getting to the use cases for the extend vote and verify what extension part, let me just remind the guarantees because this is something new. Remember, it's not agreement of consensus, it's weaker. So the guarantees that we have for correct now is that in terms of 2-3rd majority of votes will be there at the end of one consensus with their verified extension and verified by the local node. And this is our way to filter out visiting nodes. So at the end of a consensus where you will have all the votes, you need to decide that consensus plus its vote being extended in a valid way. And this information is gonna be made available at prepare proposal of the next consensus. Prepare proposal will consume that data. As a side note in our design, the extensions, they can be very variable so they are not part of the blockchain. This is something, this is all ephemeral information. It is created at the end of a consensus height in order to be consumed at the end of it, in order to be consumed at the beginning of the next one. Now that the guarantees are fresh, let's just jump into the use cases. I won't give a lot of details here because of the time restriction but just maybe in the discussion we can delve more into this but basically we can implement oracles. So validators could be connected to price sources for prices for instance and be using that information that is in principle not reliable or you don't need to agree on that information or all validators. This is not protected by consensus and just put that information in your vote extension so that at prepare proposal time, for instance, you could just as an example, take the median of the prices as they like the current price of that token or something like this. So that's a thing you could do with AVC++ and I think would be threshold encryption. So this is like something that will be helping with front running. So I think Marco has touched on this in his presentation before. So the simplest example is you have transactions that are encrypted with a public key and so all transactions in the block mempool are encrypted so nobody can front run them because nobody can understand them and then the decryption key, so the private key is split into shares and those shares are actually distributed by some means. I'm not gonna get into this here but by some days they are distributed among all the validators and so you need two thirds of those key shares in order to decrypt and this is the information you are gonna be putting on your vote extensions that will be available at the next block and only at that point you will be able to understand and execute the transactions that already made it into the blockchain in the previous height. One note here, all these use cases could be used, could be implemented using transactions, most of them at least. The difference we have here is that with vote extensions first of all it's faster because transactions remember has to be gossiped, they have to get make into the mempool, into the proposer, they have to be proposed protected by consensus so this is faster because extensions are introduced at the end of a consensus, right towards the end of a consensus execution and then they are used at the beginning of the next, the beginning of the next consensus execution so they are very fast and they are simpler in the sense that if these can be implemented with this property which is clearly weaker than agreement if we then use transactions which is basically agreement we are over killing, this is over kill, you are solving something with a property that is stronger than what you need so with extensions it's simpler. Okay, so let me just conclude my talk so I hope that in the last minutes I managed to convince you that ABCI++ enables for further flexibility, concurrency and performance that allows us to filter invalid transactions and focus on valid ones and enables new use cases that were either very cumbersome, suboptimal or even impossible before. It comes at a cost, ABCI++ requires determinism, coherence and other things, I have touched on that if the application doesn't respect those requirements then the liveness of consensus is compromised so this is serious. Something I didn't mention but probably it's worth mentioning at this point is that in any case safety is not as effective but anyway, liveness is important enough so that we take this seriously. As future work I'll just mention two things so one is the same block execution this is specified but not implemented it's basically the immediate execution that I was explaining taking to the extreme in the sense that now when you immediately execute a block at the proposal time some of the fields that now refer to the previous block because you cannot do it with the current one we are now gonna make it to refer to this to the same block that is being proposed. This simplifies troubleshooting and other things and it's kind of a more elegant way of specifying your blockchain. And the second thing I would like to touch on is both extension propagation. As I said, both extensions are not part of the blockchain they are ephemeral information so there's the problem where a process falls behind, what to do with this process what is the information it needs in order to be able to contribute to the latest consensus when it catches up. We have an implementation today that we have shown correct it is correct but it is somehow suboptimal so we're working on a formalization to come up with the first formal model of what would be the best solution for it and then implementing and just the references again is the spec so everything I've been discussing here is dealt with at length in this specification everything I have discussed here and more. And just as a final slide, a little bit of like acknowledgement so there are countless people that have the ideas via discussions in Slack via discussions in meetings that have contributed to this I'm sure I'm leaving somebody out and I apologize for that. And just like in the last months this has been a collaboration between two organizations, Informal Systems and InterGen, BNBH both at the specification and implementation levels. So this is everything. I think there is some time left now for questions and other than that, we can actually take other questions in the chat or in the Slack channel. Thank you for the great folks here. We do have a few questions. So first of all, I mean, if you're watching us on YouTube, I believe you can ask questions on YouTube but it's easier to come to the Slack channel and ask if you're on Zoom, you can also ask it there. We do have a number of questions on the Slack channel mainly and the first one is from Marco. So I'll just let him ask it himself if he wants to. Yeah, Sergio, maybe I can ask my both questions so we don't switch. But on slide number 12, you mentioned this prepared proposal, right? Yeah. In Tendermint. So where physically does this happen? So this is where I guess when the node which is a follower receives the first Tendermint consensus message from reader which would be proposed in PBFT, is this right or not? So in terms of Tendermint, in the Tendermint terminology it is gonna be the proposal node. So this is the node that in the first phase of the algorithm is gonna broadcast the proposal that everybody else has to vote on. So at every height, of course, in every height there can be, this is the test of consensus of Tendermint. So at every height, there might be a sequence of rounds but just to simplify, if the network behaves synchronously there are no Byzantine nodes, there is nothing that are no bad news to report. Then there's gonna be only one round for every height. So in that round, there will be one process that is chosen deterministically. So it is actually a local algorithm, deterministic algorithm that everybody runs. So every node runs. And so this will result into the identity of one of the validators. And this simple validator is the one that is going to propose. So before proposing, we're gonna call the application to say, hey, wait a minute, is this proposal okay? Is there anything you want to change? Okay, but if this whole node, let's say client and server in the same machine. So if the machine is Byzantine, then basically the application says whatever it wants but then the proposal still comes. Yes, yes, yes. And then you're still ordering some garbage or? Yes, so if you consider the node Byzantine, the way I think about this is like, there is no modularity to be respected. There are no properties to be respected. The thing is totally arbitrary. So all we can reason about it is like, what is the information that this node as proposer is gonna make available via the network to other nodes? And as you said, this could be one example, one typical example would be a massive block full of garbage transactions. And so these in the previous interface, there was no mechanism that we could filter. Actually, that is not true. There is a mechanism, but this mechanism is proof of stake. So if you detect that behavior, remember that the validators usually have a sizable stake and so you could still manually detect that and punish it. But there was no direct way at the interface level to detect and filter that. So those kind of garbage blocks could make it to the final, they could be decided and therefore be part of the final blockchain and you could actually go there in a block explorer and see, oh, at height 23, there was this massive block where all the transactions were basically fuzzing. So just to make sure I understand. So with the ABCI++, it's still possible that this happens if the whole proposer machine is Byzantine. So it is still possible that this machine sends it. There's no solution to that. However, when this block is now received early on in the consensus, since the application is involved now, the application can inspect those transactions and reach the conclusion this is coming from a Byzantine node and therefore filter this problem at the proposal level and therefore this will never be decided. So then if you look at the blockchain, you will never see such a block there if of course the application is well implemented in terms of prepare and process proposal. So process proposal is then run by the followers and prepare a proposal. Yes, process proposal. Sorry, I should have made that clear. Yes, yes. There's one proposer and all the rest are basically getting that proposal that is prepared by the sender's application and all the others are just deterministically remember that that's important. Deterministically accepting or rejecting that proposal and only rejecting in the case they reached the conclusion that this proposal is invalid because it's coming from, if it's invalid means it's coming from a Byzantine node because correct nodes are not supposed to propose invalid values. And what invalid means here, it's at the level of the application. It changes from application to application. However, the API and the consensus part, we can reuse it as is. And the properties I mentioned in my presentation, they don't change because they don't rely. On one side, they don't rely on the application logic and they also don't rely on the consensus logic. So you can reason about those properties from each of, from like northbound and southbound in the same way. Okay, so let's switch to Matei who has the next question and then I'll come back because just time-wise I don't want to, maybe it's more fair to through the questions first come first out. Thank you. Thank you, Marco. And actually it is related. So I think it's better to pose the question now. So let me just summarize. So basically what you were just discussing now was a way for an honest node to tell a transaction that is wrong even before proposing it, right? Not exactly so. So if the node is, if the proposal is visiting there's no way you can filter it before proposing because it's gonna- No, if the proposal is correct. Oh, if the proposal is correct, then the proposal has to be correct. Yes, that's what I mean. So this mechanism of prepare proposal is basically enabling a correct node to affect faulty transactions early and not even inject them. Whereas before even a correct node did not have this Sorry, I misunderstood your question exactly. So prepare proposal, what you basically typically are doing is you get the proposal from consensus which is just taking some set of outstanding transactions and the way you typically implemented is, well, you see if first of all you need, you see if you need to reorder some transactions, imagine token transfers. So tokens transfers, their validity depends on their relative order. So probably you wanna come up with an order to maximize the number of valid transactions that are there. And then basically you can start executing one by one. And if one of them, when you execute it, isn't valid, you actually exclude it from the proposal because remember, this is as you rightly said, this is before proposing. So you still have the opportunity to exclude transactions that are actually not gonna be valid. And this is something that before were not possible because all this work was being done at consensus level. So there are, I mean, in ABCI, there are mechanisms to exclude invalid transactions, but those mechanisms don't give you 100% certainty that you're gonna filter out all invalid transactions. It's just a weak check called check TX that you can actually execute and filter obviously bad transactions, but you don't have the guarantee that no invalid transactions is ever gonna make it to the blockchain. Thank you. And my actual question was that all this, the prepare proposal and even the process proposal, so it looks like it has to be independent of the application state. Is that the case? Yes. Okay, that is a very good question. I didn't touch on my presentation. So let's assume you are immediately executing it because it's the most complex problem. So if you are immediately, you don't have to as I said, but if you are immediately executing is, the only way you can guarantee 100% valid transactions then what you do is you execute the code. So your execution can only depend on the previous state from the previous consensus and the input you get from the block. So the transaction that you are executing at this point, nothing else. It has to be, so you can be non-deterministic, prepare proposal can be non-deterministic, but and then when you execute this, you cannot apply it blindly because you don't know, you're not sure yet, this is gonna be the value of, most of the time it's gonna be, but it might be the case that that's why we need consensus that it is not the case. And therefore the state transition has to be kept somewhere in memory. We call this candidate state. And once you get the decision, once you get the finalized block, you compare, say, oh, it's the same block I already prepared or I already processed. So I can just blindly apply the work that I did before. But at the point you are doing prepare proposal and process proposal, you cannot modify the main state of your, in the main replicated state of your application. Yes. So what you're doing in the end is some sort of speculation basically. Yes, yes. I saw in Marco's slides this speculative execution, I think he was calling it. This is a flavor of this, yes, indeed. But I insist this is not mandatory. So an application that does not do that is not violating the properties that are the requirements that I was mentioning. It is not. However, if you don't do that, there's not gonna be 100% certainty in your application that you won't end up with an invalid transaction in the blockchain. Yeah, thank you very much. I guess I give the word back to others. It looks like Sergei had the same question, but if not Sergei, go ahead. Otherwise, Marco, go ahead. I think it's roughly the same. I was just wanted to clarify if this check, this external validity, is it per high? Does it depend on already decided deliberate values on the current state? Or can it depend? Or maybe it must be independent of the state. That was the question. Okay, the answer is, okay. The answer is, I'm trying to find a simple or a concise way of answering this. So I believe you are referring to process proposal. So when you receive a proposal from the network and you wanna make sure that you want to vote for it or not. Yes. So there, so, okay. So the short answer is, you're right. The only thing, you know, the typical things you do to implement that is you can only depend on the previous state. So the state resulting from the latest height that you applied before starting this one. And the information that you get from the block, which usually is gonna be a set of transactions, but not only, there are other things that you are gonna be getting there. So- Okay, so I see that the nodes are allowed to rely to include the already decided state. For the previous height. For the previous height. Yeah, yeah, yeah. For the previous height. No, this is the concise answer. The extended answer would be like, we don't require that directly. We require that indirectly via the formal requirements. If you want to be deterministic, I don't see another way of doing it. You know, in the end, the requirements that you are deterministic, that if you are- No, I mean, we can just do weak checks on the validity of transactions. We check, okay, the transaction is well-formed, but we don't check if it makes sense in the currently proposed block at this height. That is allowed. And we could check like, if it's in general, a valid transaction looks like a valid transaction. And I see that you allow more strict checks that actually test if these transactions make sense at this height already. So both approaches are possible. So the ones I focused more on the presentation was kind of the most attractive one to me, which is guaranteed that no invalid transactions made it to the blockchain. But our requirements don't force you, application developer, to do all those checks. As you said, if you are doing some weak checks and then you are accepting the fact that some of the transactions might end up being valid when they are decided, this is okay also from the point of view of ABCI plus plus. It isn't, you are not abusing the... So this is allowed. This is not violating the properties. It's just that of course, since you are making less effort at checking in a proposal time, you are getting like weaker properties at decision time. Yeah, it's clear. I see just that it wouldn't be possible to run two proposals like ahead of time. Like to propose the block height plus two before the block height plus one is already decided. Like would be more co-location. That is an excellent idea. But we are run out of time. Yeah, it's an excellent idea. Thanks for this idea. I actually hadn't considered this. This is probably like a super interesting potential future where we can have here in order to optimize the execution. Thanks for that idea. All right, fantastic. So thank you for the great questions. Thank you again, Sergio, for your talk and for the answers.