In this post you’ll learn about Taiko (a Based Rollups), and how block building works in Taiko.
Special thanks to dmarz (Flashbots), David Cai (Taiko), and horsey (Taiko) for their feedback on this writeup and clarifications on how Taiko works.
TL;DR
- Based Rollups claim to offer more revenue to Ethereum and can provide synchronous transactions across L2s.
- Taiko is a layer 2 Based Rollup with a public mempool that allows anyone to propose blocks via the L1.
- Activity on Taiko consists of mostly farming transactions.
- Block builders can PGA each other. Writeup by Davide Rezzoli.
Why care about Based Rollups?
The main thesis behind Based Rollups is that they offer a more attractive revenue story for the Ethereum network as opposed to current Optimistic Rollups, which many claim are extractive with little of the fees going into Ethereum as seen below.
Source: Blockworks (Tweet)
Additionally, the recent push for interoperability provides another thesis where Based Rollups provide synchronous transactions across different L2s.For example, if you have funds on rollup A and want to buy an NFT on rollup B, you may have a situation where you initiate the bridge from rollup A but somebody else buys the NFT before your bridge completes. This leaves you with a partially complete transaction. However, if rollup A and rollup B were both Based Rollups and a Based Rollup Block Builder received both your bridge tx + NFT buy tx across two different chains at the same time, then they can order the bridge tx in front of the NFT buy tx within the same block. This removes the latency of having to wait for the block with the bridge tx to complete before initiating the NFT buy tx.
Overview of Taiko’s Numbers
An upward trend in the number of addresses (not necessarily users) on Taiko.
- 25 TPS daily on average
- 300,000 active addresses
- ~1000 transactions per block, however 125,000 byte blocks sizes similar to Ethereum.
- This makes sense give the spam nature of most transactions, and spam txs are smaller because they’re cheaper.
What are these transactions for? Most activity on Taiko is currently farming activities, such as minting / burning WETH, attestations on RubyScore.io (chain activity leaderboard), and quest games like Robots.Farm. There is currently not much DeFi activity.
MEV Supply Chain
Note: The upper layer is Taiko, and the bottom layer is Ethereum.
Adding Taiko to the iconic MEV Supply Chain diagram, there is now a new layer where a user sends a transaction into Taiko’s mempool, the mempool sends a list of pending transactions to the Taiko Block Builder, the block builder then proposes a block to the Taiko smart contract on Ethereum, and lastly a prover submits a proof of the block to the same smart contract.
High Level Overview of Block Building on Taiko (Alethia)
The diagram above showcases the high level overview of block building in Taiko. Overall, a block gets proposed (steps 1 & 2), proved (steps 3 - 5), and verified (step 6).
Prover Market
Source: https://www.youtube.com/watch?v=9LT6B1pgkI8&t=70s
In step 2 of the block building diagram above, I mentioned that a proposer can either submit the proof themselves or select a prover is selected from a prover market. What is a prover market?
In Taiko, multiple provers offer themselves and their proving fee to be picked by the block builder for proving their block. This is what’s known as a prover market, and is how a block builder selects a prover.
What if a proof is contested (pre-Alethia)?
Taken straight from Taiko’s docs: Contestable Rollups | Docs
- If the contester wins:
- The contester receives the contestation bond back and 1/4 of the original prover’s bond.
- The new prover receives 1/4 of the original prover’s validity bond as a proving fee.
- 1/2 of the original prover’s bond is sent to the DAO treasury.
- If the original prover wins:
- The original prover gets back the validity bond and 1/4 of the contest bond as a reward.
- The new prover earns 1/4 of the contest bond.
- 1/2 of the contest bond goes to the DAO treasury.
Note that post-Alethia upgrade, proofs can not be contested as the protocol fully trusts ZK verifiers.
Taiko DAO economics
Currently in testnet, Taiko plans to launch a DAO containing a treasury used to fund the development of Taiko & Taiko’s ecosystem.
Revenues to the treasury consist of 25% of tx base fees (ETH), and pre-Alethia upgrade 50% of contested proofs fees (TAIKO).
PGA Example
In Taiko, there can be seen multiple blocks being proposed at the same timestamp, with one block containing the majority of transactions. Block proposers earn transaction fees from the transactions included in their block. As a result, the block proposer that PGA’s successfully is able to earn the transaction fees.
The block with minimal transactions attempted to propose those transactions in their block, however it did not get included because the transaction was already included in another block.
For more details, checkout “Understanding Based Rollups: PGA Challenges, Total Anarchy, and Potential Solutions” by Davide Rezzoli
How is PGA done?
- Block Builder A builds a block using transactions from Taiko’s memepool.
- Block Builder A proposes the block via
proposeBatch()
tx into TaikoL1 smart contract in Ethereum. - Block Builder B sees Block Builder A’s
proposeBatch()
tx in Ethereum’s mempool. - Block Builder B builds their own block with their own (possibly the same) order of pending tx’s in Taiko’s mempool.
- Block Builder B submits their own
proposeBatch()
tx with a higher gas fee. - & 7. Block Builder A and Block Builder B both have their blocks included, however Block Builder B’s block contains all the txs (and tx fee rewards), and Block Builder A’s block is empty.
Note that block proposers are also seen submitting their block to a private mempool to counteract above.
For more details about PGA, checkout “Understanding Based Rollups: PGA Challenges, Total Anarchy, and Potential Solutions” by Davide Rezzoli
What’s inside “empty” blocks?
In the PGA example, there were “empty” blocks that only had a 1 transaction instead of 0. Why not 0 transactions?
This is because Every block contains a AnchorV3 tx which is added to the start of the block during the block building process. This Anchoring transaction is used to synchronize information between the L1 and Taiko.
In-depth overview of Block Building (Taiko Alethia)
Terminology:
- A batch consists of multiple blocks.
- ChainSyncer, Proposer, and Prover are part of taiko-client, which is the consensus client. Taiko-Geth is the execution client, and TaikoL1 (deployed on Ethereum) & TaikoL2 (deployed on Taiko) are smart contracts.
- (For Taiko’s fallback proposer specifically) In
proposer
a timer is randomly set between 12 to 120 seconds for when to propose a block. - Once the timer is finished,
ProposeOp()
fetches transactions from L2 mempool and proposes them as a block toTaikoL1
.txLists
generated fromfetchPoolContent()
taiko-mono/packages/taiko-client/proposer/proposer.go at 6ab0ecd4d40f736158a63e66616f697972916a8f · taikoxyz/taiko-mono · GitHubfetchPoolContent()
does an API call totaiko-geth
which returns list of transactions from mempool with a miner tip. taiko-geth/eth/taiko_api_backend.go at cdca79128bc606f89c12e08474f228ad5d0d89c3 · taikoxyz/taiko-geth · GitHub
ProposeTxListPacaya()
sendsproposeBatch()
transaction toTaikoL1
smart contract. taiko-mono/packages/taiko-client/proposer/proposer.go at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub- In this process, a check to ensure the proposer has enough TAIKO for the LivenessBond is conducted. taiko-mono/packages/taiko-client/proposer/proposer.go at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
proposeBatch()
transaction is built in this part of the code. taiko-mono/packages/taiko-client/proposer/transaction_builder/blob.go at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
TaikoL1
’sproposeBatch()
is called onchain by any block proposer.- The parameters to be used for building a batch (blocks) is validated. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
- The metadata for the batch of blocks is created. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
- The batch is stored onchain. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
- Proposer assigns a Prover to prove the batch, and Prover pays a 125 + 5 * num_blocks liveness bond. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
- Note that the Proposer can also be the Prover if they do not use the Prover Market. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 75db2c2082e966b51f09680b8c558a7068a3e001 · taikoxyz/taiko-mono · GitHub
BatchProposed
event emitted
- Block is proved by a Prover.
- Prover listens for
BatchProposed
events to determine if a proof needs to be requested for a block. taiko-mono/packages/taiko-client/prover/prover.go at e10c62f9688cfe2db509435a0c7829591794307e · taikoxyz/taiko-mono · GitHub- When a prover sees a new block via
blockProposedHandler.Handle()
from above, it submits a ProofRequestBody message. taiko-mono/packages/taiko-client/prover/event_handler/block_proposed.go at e10c62f9688cfe2db509435a0c7829591794307e · taikoxyz/taiko-mono · GitHub
- When a prover sees a new block via
- Upon seeing a proof request message, a proof is requested and generated via
requestProofOp()
taiko-mono/packages/taiko-client/prover/prover.go at e10c62f9688cfe2db509435a0c7829591794307e · taikoxyz/taiko-mono · GitHub - A proof is submitted via
submitProofOp()
taiko-mono/packages/taiko-client/prover/prover.go at e10c62f9688cfe2db509435a0c7829591794307e · taikoxyz/taiko-mono · GitHub
- Prover listens for
chain_syncer
picks upBatchProposed
event from L1 and inserts them into L2 chain.- taiko-mono/packages/taiko-client/driver/chain_syncer/blob/syncer.go at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
- Iterates over all events seen on the L1. taiko-mono/packages/taiko-client/driver/chain_syncer/blob/syncer.go at 6ab0ecd4d40f736158a63e66616f697972916a8f · taikoxyz/taiko-mono · GitHub
insertNewHead()
is called to insert the block into the L2. taiko-mono/packages/taiko-client/driver/chain_syncer/blob/syncer.go at 6ab0ecd4d40f736158a63e66616f697972916a8f · taikoxyz/taiko-mono · GitHubAnchorV3
tx is inserted to the very start of every block. taiko-mono/packages/taiko-client/driver/chain_syncer/blob/blocks_inserter/pacaya.go at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHubExecutionPayload
is created via Engine API calls between the client (consensus) and taiko-geth (execution), and the block is now inserted into the L2. taiko-mono/packages/taiko-client/driver/chain_syncer/blob/blocks_inserter/common.go at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
- Batch is verified.
verifyBatches()
is called at the end of step 3’sproposeBatch()
. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub- If the batch was proved within the proving time, the full 125 Taiko * num_of_blocks Liveness Bond is returned to the Prover. Otherwise, only half the amount is returned. taiko-mono/packages/protocol/contracts/layer1/based/TaikoInbox.sol at 4a9202fffac67f14678a34daac6b0e6050fe7f64 · taikoxyz/taiko-mono · GitHub
BatchesVerified()
event is emitted.