This is a joint post from Nomadic Labs, Marigold, TriliTech, Oxhead Alpha, Tarides, DaiLambda, Functori & Tweag.
In a recent blog post, we reported two critical bugs in the original Jakarta protocol proposal, affecting the implementation of the experimental Transaction Optimistic Rollups (TORUs) feature.
Fortunately, we have been able to confidently fix both issues, and a new protocol proposal, Jakarta 2, has been since developed, tested and released. Moreover, the latter proposal — whose “real name” is given as usual by its hash, PtJakart2xVj7pYXJBXrqHgd82rdkLey5ZeeGwDgPp9rhQUbSqY
— has already been injected and it is already competing with the original Jakarta one in the current Proposal period.
Yesterday, Nomadic Labs published a release candidate for a new Octez suite version, v13.0~rc1
. This release candidate includes the daemon binaries that enable testing the Jakarta 2 protocol proposal in the upcoming Jakartanet
test network.
Changes in Jakarta 2
The changes in Jakarta 2 with regard to the previous Jakarta proposal concern only fixing the reported bugs. In this section we shed more light into these issues, and detail how they were corrected for the new protocol proposal.
Bugfix for uncraftable rejection operations
The first bug concerns rejection operations, that is the Layer 1 operation which allows a honest node to refute an erroneous or malicious commitment in a TORU. A flaw in its implementation ultimately made it possible for an attacker to publish commitments whose refutation proofs would not fit within the maximal allowed size for Tezos’ manager1 operations batches — 32 KiB.
This limit underpins a design decision in the current implementation of TORUs: there is an upper-bound on the number of Layer 2 transaction batches from the same rollup which can be (ahem!) rolled up within a given Tezos Layer 1 block. For each of these batches, operators of the client rollup are required to include the batch’s hash in their respective commitment operation on Layer 1. Inserting too many batches from the same rollup in the same block would make it impossible to insert a valid commitment for it in a subsequent block, which would result in the incriminated rollup being stuck forever.
Rejection operations denounce a specific rollup commitment, which contains one hash per batch of Layer 2 transactions. Honest rollup accusers can trivially find the first hash that they disagree with, and craft a rejection operation to refute said batch. The rejection operations requires two key pieces of data: (1) the target batch itself, and (2) a collection of Merkle proofs which allow to replay said message. This raises an immediate concern. What if the provided Merkle proofs are just too large to fit within the size boundaries a Tezos Layer 1 manager operation? If the batch is large enough (that is, it contains enough transactions), this can definitely happen.
To tackle this risk, TORUs relies on two design choices. First, TORUs encode Merkle proofs using a format that allows to send truncated proofs. Second, a batch for which one can exhibit a valid, “large enough” truncated proof has to be considered a no-op.
In the first Jakarta proposal, the size boundary for Layer 2 operations batches was 5 KB, and a truncated proof larger than 30 KB was required, in order to prove that a batch should be considered a no-op
. So, in order for an honest rollup node to prove that a batch of size 5KB was to be ignored, it needed to produce a refutation whose size was at least 35 KB (~36 KiB)… which does not fit within the 32 KiB limit on Layer 1.
The fix is straightforward: accept a truncated proof of 30KiB - sizeof(batch)
. In this way, rejection operations are guaranteed to fit within a single Tezos manager operation. The curious reader can have a look at the diff of the MR implementing this bugfix.
Bugfix for forged zero-valued Tickets
The second bug concerns Tezos Tickets. The latter are an abstract representation of tokenized assets, and in TORUs, they are used to represent the assets deposited and transacted within the rollup.
Tickets can be seen as a tuple consisting of: (1) its (typed) payload, (2) the address of the smart contract which has minted it — a.k.a its ticketer — , and (3) a quantity. A ticket can be split into two (and eventually more parts), assuming that the total sum of the quantities associated to each of the two resulting half-tickets is equal to the amount of the original one. Dually, two tickets with the same payload and issued by the same ticketer, can also be joined, adding up the quantities.
A subtle, and often-overlooked detail is that a zero-valued Ticket is a completely valid one. In a nutshell, owning a ticket whose quantity is 0 is not the same thing as not owning any ticket at all — and the consequences or the semantic meaning of the former depends on the application.
Both with TORUs and the Tezos protocol’s Table of Tickets2 specific design choices concerning zero-valued tickets were made, in order to simplify each component’s designs. On one hand, the Table of Tickets does not take into account zero-valued tickets at all. This is a legitimate choice, because its purpose is to prevent the forgery, and the incorrect splitting, of tickets holding non-zero quantities. On the other hand, in TORUs we have decided to not support zero-valued Ticket transfers within the Layer 2, and to rely on the Table of Tickets to transfer ticket ownership in the Layer 1. In the end, these choices were proven to be incompatible, was the TORU implementation relied on stronger assumptions than those provided by the Table of Tickets. As it is often the case in Software Engineering, composing two software components brought unforeseen issues in the resulting system.
In Jakarta 2, we addressed this situation by enforcing in a stricter manner that zero-valued tickets are not supported within the rollups, adding additional checks in the Tezos protocol’ Layer 1. More precisely, three straightforward bound checks are enough to prevent zero-valued tickets being forged by TORUs withdrawal operations.
Join Jakartanet!
A testnet for the Jakarta 2 protocol proposal, named Jakartanet
, will launch on April 27th at 15hs UTC. It is critical to have as many bakers as possible participating in this testnet, by running nodes, producing blocks and
deploying apps. We are looking for more bakers to participate from day one. If you are interested, please join the Tezos Baking slack and make yourselves known in the #test-networks
channel.
Once more, we strongly encourage you to test your own Tezos-based applications to check for compatibility problems.
Should the Jakarta 2 protocol proposal be accepted by the community, the following minimal version of Tezos node (shell) software will be necessary to participate in the consensus, due to necessary changes introduced to the protocol environment: v13
of Octez, or v3
of TezEdge.
-
Manager operations is the term we use in the Tezos architecture to denote any fee-paying operation in competition for block space, like transfers, smart contract originations, and smart contracts calls. Thus, the new Layer 1 operations related to rollups belong to this category as well (see here for more details). ↩
-
the Table of Tickets, introduced in Jakarta, is an internal component of the Tezos economic protocol who keeps track of all emitted tickets in the current context — that is at the current head of the blockchain. ↩