Skip to content

Commit

Permalink
fix(docs): fix outdated documentation and simplify explanations (#14653)
Browse files Browse the repository at this point in the history
Co-authored-by: David <[email protected]>
  • Loading branch information
adaki2004 and davidtaikocha authored Sep 7, 2023
1 parent e25e0cd commit f16d45d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 114 deletions.
49 changes: 14 additions & 35 deletions packages/website/pages/docs/concepts/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ the same mechanism is used on Ethereum it allows Taiko to be Ethereum equivalent
(with some small implementation detail changes) even for this part of its network,
which is not obviously the case for L2s.

## EIP-1559 powered prover fees
## Off-chain proof market

Proving blocks requires significant compute power to calculate the proof
to submit and verify the proof on Ethereum. Provers need
Expand All @@ -71,40 +71,19 @@ to pay for a proof is not obvious however:
4. The proof generation cost depends on how fast a
proof needs to be generated.

Because the proving cost impacts the transaction fees
paid by the users, the goal is to pay only as much as
required for the network to function well. This means not
underpaying provers because blocks may remain unproven,
but certainly also not overpaying provers so that it doesn’t
make sense to incur very high costs to try and generate
proofs as quickly as absolutely possible. A good balance is
key to a well working solution that takes into account the
needs of the different network participants.
It’s clear that a fixed proving fee does not work. The
protocol should also not be dependent on a single prover
for a block because this will put too much power in the
hands of a single entity that can impact the stable progress
of the chain.

The network, somehow, has to find the correct price between
two resources where the demand/supply is ever changing.
We can model this problem as a market between the proving
fee (per gas) per proof delay (per time unit), striking
a dynamic balance between proving cost and proof delay.
An additional complication is that the protocol expects
the block proposer to pay the proving fee at block proposal
time. As such, the baseFee of this model is used to charge
the proposer of a block using the total gas used in the block.
This is only an estimate of the actual cost because the
actual cost is only known when the proof is submitted. If
the estimated cost was too high the difference is returned
to the block proposer and the baseFee is decreased. If
the estimated cost was too low extra Taiko tokens are
minted to make up the difference and the baseFee is
increased. To lower the chance that the estimated cost is too
low and extra Taiko tokens need to be minted, a slightly
higher baseFee can be charged to the proposer than the
one predicted by the model.
In the pursuit of optimizing network efficiency and balancing costs, the ecosystem introduces a robust off-chain proof market. Proposers, on a per-block basis, actively seek potential proof service providers through this dynamic marketplace. A pivotal component of this setup is the publicly exposed API, providing proposers with the means to query and engage with available proof providers off-chain.

When an agreement is reached concerning the proving fee for a specific block, the chosen proof service provider is then tasked with granting a cryptographic signature to the proposer. This signature serves as a binding commitment, signifying the prover's dedication to delivering the proof within the agreed-upon timeframe.

Provers within this off-chain proof market come in two primary forms: Externally Owned Accounts (EOA) and contracts, often referred to as Prover pools. To qualify as a Prover pool, a contract must adhere to specific criteria, implementing either the IProver interface, as previously defined by Taiko, or the IERC1271 (isValidSignature) interface.

Upon a proposer's submission of a block, the signature granted by the chosen provider is subjected to verification. Any deviations result in a reverted transaction.

As an additional incentive for proposers, the system incorporates the issuance of TKO tokens. This serves as an extra motivator, as proposing blocks alone may not always prove profitable, especially when considering Ethereum's on-chain fees plus the proving fee. The issuance of TKO tokens operates on a dynamic 'emission rate per second,' comparing each block proposal to the last.

The reward depends on the proof service provider and the agreement. For EOAs and Prover pools that implement the IERC1271 interface, the reward is disbursed in ETH. However, in cases where providers implement the IProver interface, the prover fee can be ETH, any other ERC20 tokens, or even NFTs, based on the negotiated terms.

To add a layer of security and commitment to the process, provers must provide a substantial amount of TKO tokens per block, effectively serving as insurance. In the unfortunate event of a failure to deliver the proof within the given time, a portion, specifically 1/4, is directed to the actual prover, while the remaining 3/4 are permanently burnt. Conversely, successful and timely proof delivery ensures the return of these tokens to the Prover.

## EIP-4844 scaling via blob data

Expand Down
89 changes: 15 additions & 74 deletions packages/website/pages/docs/concepts/proposing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,86 +8,27 @@ On Taiko, the next L2 state is known immediately and deterministically at the ti
- IF every transaction in the list is valid, an ordered subset of the list is created by skipping over transactions which have an invalid nonce or the sender has too little Ether balance to pay for the transaction. This ordered subset is used along with the [anchor transaction](./proposing#anchor-transaction) to create a Taiko L2 block.
- IF any transaction in the list is invalid, an empty block (with only the anchor tx) is created on L2.

## Intrinsic validity functions
## Building the blocks

The Ethereum yellow paper has a well defined set of rules to compute the state transition. We use these same rules to take a proposed block, and compute the post-block state on Taiko. A proposed block on Taiko has two parts:
The Ethereum yellow paper has well-defined rules to compute the state transition. We use these same rules to take a proposed block, and compute the post-block state on Taiko. The high level overview of creating L2 blocks as follows:

- The block metadata
- A list of transactions (stored in a blob, and the block metadata stores the hash to this blob)

We divide the yellow paper validity checks into two parts:

- **Proposed block** intrinsic validity function
- **Transaction list** intrinsic validity function

A proposed block must pass these two checks in order to map the txList to an L2 block on Taiko. If a block passes the proposed block validity function but later fails the transaction list validity function, an empty block will be created.

### Proposed block intrinsic validity function

The formal specification of the proposed block intrinsic can be found in the [whitepaper](https://taikoxyz.github.io/taiko-mono/taiko-whitepaper.pdf), but on a high level, the proposed block intrinsic validity function checks that the block is valid except for transaction list validity checks. This is separated because on TaikoL1, the transaction list is not known and stored as a data blob. It would also be too expensive to do these checks on L1.

| Name | Symbol | Meaning |
| ----------------------- | ----------------- | -------------------------------------------------------------------------------------------------------- |
| **Block Metadata** | $C$ | The block metadata. |
| **id** | $C_i$ | A value equal to the number of proposed blocks. The genesis block has an id of zero. |
| **beneficiary** | $C_c$ | The 20-byte address to which all transaction fees in the block will be transferred. |
| **timestamp** | $C_s$ | The timestamp used in the block, set to the enclosing L1 timestamp. |
| **mixHash** | $C_m$ | The mixHash value used in the block, set to the enclosing L1 mixHash. |
| **txListHash** | $C_t$ | The Keccak-256 hash of this block’s txList (KZG commitment after EIP-4844). |
| **l1Height** | $C_a$ | The enclosing L1 block’s parent block number. |
| **l1Hash** | $C_h$ | The enclosing L1 block’s parent block hash. |
| **TaikoL1** | $R$ | The TaikoL1 contract. |
| **numProposedBlocks** | $R_i$ | The current number of proposed blocks (the `id` for the next proposed block is `numProposedBlocks + 1`). |
| **lastVerifiedBlockId** | $R_f$ | The last verified block id. |
| **txList** | $L$ | The list of transactions in a proposed block. |
| **txListSizeInBytes** | $\lVert L \rVert$ | The transaction list size in bytes. |

The proposed block intrinsic validity function checks that all these conditions are met:

1. $R_i \le R_f + K_{MaxNumBlocks}$ (the block id is not too far ahead)
2. $\lVert L \rVert \gt 0$ (transaction list is not empty)
3. $\lVert L \rVert \le K_{MaxTxListSizeInBytes}$ (transaction list does not exceed the maximum size)
4. $C_c \ne 0$ (beneficiary is not zero)
5. $C_i = R_i$ (block id is correct)
6. $C_s = \text{TIMESTAMP}$ (timestamp is correct)
7. $C_m = \text{DIFFICULTY}$ (mixHash is correct)
8. $C_t \ne 0$ (txListHash is not zero)
9. $C_a = \text{NUMBER} - 1$ (l1Height is correct)
10. $C_h = \text{BLOCKHASH}(C_a)$ (l1Hash is correct)

### Transaction list intrinsic validity function

The transaction list intrinsic validity function checks that the transaction list is valid and each transaction in the list is valid.

A transaction list is valid if and only if:

1. The transaction list is well-formed RLP, with no additional trailing bytes (rule #1 in Ethereum yellow paper).
2. The transaction list is no larger than $K_{TxListMaxBytes}$.
3. The sum of all transactions' gas limit is no larger than the protocol constant $K_{BlockMaxGasLimit}$.
4. The total number of transactions is no larger than the protocol constant $K_{BlockMaxTxs}$.

A transaction is valid if and only if:

1. The transaction is well-formed RLP, with no additional trailing bytes (rule #1 in the Ethereum yellow paper).
2. The transaction's signature is valid (rule #2 in Ethereum yellow paper).
3. The transaction's gas limit is no smaller than the intrinsic gas $K_{TxMinGasLimit}$ (rule #5 in the Ethereum yellow paper).

If any of these fails, an empty block will be created on L2 (with only the anchor tx).
1. The system starts by creating a new L2 block with an anchor transaction. This anchor transaction is always the first transaction in the block even if the block is empty. (More about anchor transactions in the next section.)
2. There are validity checks performed at the node (or sometimes protocol) level as well:
2.1 Asserts that the length of the transaction list does not exceed a predefined maximum (MAX_TX_LIST_BYTES), ensuring that the list is within the limits.
2.2 The transaction list is (RLP) decoded into a list of transactions (txList). If the bytes are not decodeable it will result in an empty block.
2.3 The amount of gas required to include transactions is available. (If a transaction cannot fit into a block, it is simply excluded from it, but the block is still valid with other transactions.)
2.4 The transaction signature is valid.
2.5 The transaction nonce is valid.
2.6 The sender account has no contract code deployed (EIP-3607).
2.7 The transaction's gas limit is no smaller than the intrinsic gas.
2.8. The sender has enough balance to cover the transaction (gasLimit * gasPrice + tx.value).

## Anchor transaction

The anchor transaction is a way for the protocol to make use of the programmability of the EVM (which we already need to be able to proof) to enforce certain protocol behavior. We can add additional tasks to anchor transactions to enrich Taiko’s functionalities by writing standard smart contract code (instead of requiring more complicated changes to Taiko’s ZK-EVM and node subsystems).

The anchor transaction is required to be the first transaction in a Taiko block (which is important to make the block deterministic). The anchor transaction is currently used as follows:

1. Persisting `l1Height` $C_a$, `l1Hash` $C_h$, `l1SignalRoot`, and `parentGasUsed` (data inherited from L1) to the storage trie. These values can be used by bridges to validate cross-chain messages.
2. Comparing $ρ_{i1}$, the public input hash stored by the previous block, with `KEC(i − 1, d, h[2..256])`. The anchor transaction will throw an exception if such comparison fails. The protocol requires the anchor transaction to execute successfully and will not accept a proof for a block that fails to do so. Note that the genesis block has $ρ_0$ ≡ `KEC(0, d, [0, ..., 0])`.
3. Persisting a new public input hash $ρ_i$ ≡ `KEC(i, d, h[1..255])` to the storage trie for the next block to use. This allows transactions, in the current and all following blocks, to access these public input data with confidence as their values are now covered by ZK-EVM’s storage proof.
4. With anchoring, the block mapping function `M` (defined in the [whitepaper](https://taikoxyz.github.io/taiko-mono/taiko-whitepaper.pdf)) can be simplified to:
$$
\begin{aligned}
B &≡ (H, T, U) \\
&≡ M(δ, θ, B, \dot{B}) \\
&≡ M(δ, θ, C, L)
\end{aligned}
$$
1. Persisting `l1Height`, `l1Hash` and `l1SignalRoot` to the storage trie. These values can be used by bridges to validate cross-chain messages.
2. Ensuring that the previous 256 block hashes that are exposed to the EVM are correct.
3. Calculating the EIP-1559 `basefee` which will be used on L2.
6 changes: 1 addition & 5 deletions packages/website/pages/docs/concepts/proving.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Callout } from "nextra-theme-docs";

# Proving Taiko blocks

The purpose of proving blocks is to give certainty to bridges about the execution that happened in the rollup. To rely on some state that happened inside of the rollup, a bridge will want a proof that everything was done correctly. On Taiko you can run a node as a prover and prove blocks, permissionlessly. This means that you can examine the proposed blocks on the TaikoL1 contract, and generate proofs for them. Currently, any prover can create proofs for proposed blocks. This means that the number of "state transitions" has no upper bound, because we don't know what is the correct state transition yet. Only first prover with a valid proof of the correct state transition (state transition) will receive the reward of TTKO.
The purpose of proving blocks is to give certainty to bridges about the execution that happened in the rollup. To rely on some state that happened inside of the rollup, a bridge will want a proof that everything was done correctly. On Taiko you can run a node as a prover and prove blocks, permissionlessly. This means that you can examine the proposed blocks on the TaikoL1 contract, and generate proofs for them. Currently, any prover can create proofs for proposed blocks. This means that the number of "state transitions" has no upper bound, because we don't know what is the correct state transition yet. Only first prover with a valid proof of the correct state transition will receive the reward of `ETH` (and possibly any `ERC20` or even NFTs if the Prover pool implementation favors it).

## Verified blocks and parallel proving

Expand Down Expand Up @@ -58,10 +58,6 @@ Currently, you only need a single proof from any prover to verify a block.

The oracle prover is a prover from a unique address (our own address) that is able to override the community prover. This is a safety mechanism we have in place while the ZK-EVM is still in development and in case an invalid block was marked as verified from a community proof.

### Oracle prover

A oracle prover generates a fake proof to mark a block as verified. We only require a real proof to be generated every N blocks. Otherwise, we accept a fake, oracle proof, and mark the block as verified. This is a temporary testnet feature to reduce the cost for community provers.

### The proof cooldown period

We have a proof cooldown period which is an interval of time we set after fully verifying a block. The reason we do that is to allow for a fault proof to come in, once we have a multi-prover system set in place.
Expand Down

0 comments on commit f16d45d

Please sign in to comment.