diff --git a/packages/protocol/contracts/L1/LibData.sol b/packages/protocol/contracts/L1/LibData.sol index 04c6f6aafb..0c5ec06617 100644 --- a/packages/protocol/contracts/L1/LibData.sol +++ b/packages/protocol/contracts/L1/LibData.sol @@ -45,8 +45,8 @@ library LibData { mapping(bytes32 => uint256) commits; mapping(address => bool) provers; // Whitelisted provers uint64 genesisHeight; - uint64 latestFinalizedHeight; - uint64 latestFinalizedId; + uint64 latestVerifiedHeight; + uint64 latestVerifiedId; uint64 nextBlockId; } @@ -69,7 +69,7 @@ library LibData { State storage s, uint256 number ) internal view returns (bytes32) { - require(number <= s.latestFinalizedHeight, "L1:id"); + require(number <= s.latestVerifiedHeight, "L1:id"); return s.l2Hashes[number]; } @@ -80,14 +80,14 @@ library LibData { view returns ( uint64 genesisHeight, - uint64 latestFinalizedHeight, - uint64 latestFinalizedId, + uint64 latestVerifiedHeight, + uint64 latestVerifiedId, uint64 nextBlockId ) { genesisHeight = s.genesisHeight; - latestFinalizedHeight = s.latestFinalizedHeight; - latestFinalizedId = s.latestFinalizedId; + latestVerifiedHeight = s.latestVerifiedHeight; + latestVerifiedId = s.latestVerifiedId; nextBlockId = s.nextBlockId; } diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index 2d4a8e7513..0b5debb79b 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -71,9 +71,9 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { */ function proposeBlock(bytes[] calldata inputs) external nonReentrant { V1Proposing.proposeBlock(state, inputs); - V1Finalizing.finalizeBlocks( + V1Finalizing.verifyBlocks( state, - LibConstants.TAIKO_MAX_FINALIZATIONS_PER_TX + LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX ); } @@ -97,9 +97,9 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { bytes[] calldata inputs ) external nonReentrant { V1Proving.proveBlock(state, AddressResolver(this), blockIndex, inputs); - V1Finalizing.finalizeBlocks( + V1Finalizing.verifyBlocks( state, - LibConstants.TAIKO_MAX_FINALIZATIONS_PER_TX + LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX ); } @@ -128,9 +128,9 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { blockIndex, inputs ); - V1Finalizing.finalizeBlocks( + V1Finalizing.verifyBlocks( state, - LibConstants.TAIKO_MAX_FINALIZATIONS_PER_TX + LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX ); } @@ -157,11 +157,14 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { return V1Proving.isProverWhitelisted(state, prover); } - /// @notice Finalize up to N blocks. - /// @param maxBlocks Max number of blocks to finalize. - function finalizeBlocks(uint256 maxBlocks) external nonReentrant { + + /** + * Verify up to N blocks. + * @param maxBlocks Max number of blocks to verify. + */ + function verifyBlocks(uint256 maxBlocks) external nonReentrant { require(maxBlocks > 0, "L1:maxBlocks"); - V1Finalizing.finalizeBlocks(state, maxBlocks); + V1Finalizing.verifyBlocks(state, maxBlocks); } function isCommitValid(bytes32 hash) public view returns (bool) { @@ -185,7 +188,7 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { } function getLatestSyncedHeader() public view override returns (bytes32) { - return state.getL2BlockHash(state.latestFinalizedHeight); + return state.getL2BlockHash(state.latestVerifiedHeight); } function getStateVariables() @@ -193,8 +196,8 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { view returns ( uint64 /*genesisHeight*/, - uint64 /*latestFinalizedHeight*/, - uint64 /*latestFinalizedId*/, + uint64 /*latestVerifiedHeight*/, + uint64 /*latestVerifiedId*/, uint64 /*nextBlockId*/ ) { @@ -214,7 +217,7 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { returns ( uint256, // TAIKO_CHAIN_ID uint256, // TAIKO_MAX_PROPOSED_BLOCKS - uint256, // TAIKO_MAX_FINALIZATIONS_PER_TX + uint256, // TAIKO_MAX_VERIFICATIONS_PER_TX uint256, // TAIKO_COMMIT_DELAY_CONFIRMATIONS uint256, // TAIKO_MAX_PROOFS_PER_FORK_CHOICE uint256, // TAIKO_BLOCK_MAX_GAS_LIMIT @@ -230,7 +233,7 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events { return ( LibConstants.TAIKO_CHAIN_ID, LibConstants.TAIKO_MAX_PROPOSED_BLOCKS, - LibConstants.TAIKO_MAX_FINALIZATIONS_PER_TX, + LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX, LibConstants.TAIKO_COMMIT_DELAY_CONFIRMATIONS, LibConstants.TAIKO_MAX_PROOFS_PER_FORK_CHOICE, LibConstants.TAIKO_BLOCK_MAX_GAS_LIMIT, diff --git a/packages/protocol/contracts/L1/v1/V1Events.sol b/packages/protocol/contracts/L1/v1/V1Events.sol index 90f0ca94c3..484207a34c 100644 --- a/packages/protocol/contracts/L1/v1/V1Events.sol +++ b/packages/protocol/contracts/L1/v1/V1Events.sol @@ -13,7 +13,7 @@ import "../LibData.sol"; /// @author david abstract contract V1Events { // The following events must match the definitions in other V1 libraries. - event BlockFinalized(uint256 indexed id, bytes32 blockHash); + event BlockVerified(uint256 indexed id, bytes32 blockHash); event BlockCommitted(bytes32 hash, uint256 validSince); diff --git a/packages/protocol/contracts/L1/v1/V1Finalizing.sol b/packages/protocol/contracts/L1/v1/V1Finalizing.sol index dfb7cd6c97..3ed62c9c86 100644 --- a/packages/protocol/contracts/L1/v1/V1Finalizing.sol +++ b/packages/protocol/contracts/L1/v1/V1Finalizing.sol @@ -14,7 +14,7 @@ import "../LibData.sol"; /// @author dantaik library V1Finalizing { - event BlockFinalized(uint256 indexed id, bytes32 blockHash); + event BlockVerified(uint256 indexed id, bytes32 blockHash); event HeaderSynced( uint256 indexed height, @@ -27,28 +27,28 @@ library V1Finalizing { s.nextBlockId = 1; s.genesisHeight = uint64(block.number); - emit BlockFinalized(0, _genesisBlockHash); + emit BlockVerified(0, _genesisBlockHash); emit HeaderSynced(block.number, 0, _genesisBlockHash); } - function finalizeBlocks(LibData.State storage s, uint256 maxBlocks) public { - uint64 latestL2Height = s.latestFinalizedHeight; + function verifyBlocks(LibData.State storage s, uint256 maxBlocks) public { + uint64 latestL2Height = s.latestVerifiedHeight; bytes32 latestL2Hash = s.l2Hashes[latestL2Height]; uint64 processed = 0; for ( - uint256 i = s.latestFinalizedId + 1; + uint256 i = s.latestVerifiedId + 1; i < s.nextBlockId && processed <= maxBlocks; i++ ) { LibData.ForkChoice storage fc = s.forkChoices[i][latestL2Hash]; if (fc.blockHash == LibConstants.TAIKO_BLOCK_DEADEND_HASH) { - emit BlockFinalized(i, 0); + emit BlockVerified(i, 0); } else if (fc.blockHash != 0) { latestL2Height += 1; latestL2Hash = fc.blockHash; - emit BlockFinalized(i, latestL2Hash); + emit BlockVerified(i, latestL2Hash); } else { break; } @@ -56,10 +56,10 @@ library V1Finalizing { } if (processed > 0) { - s.latestFinalizedId += processed; + s.latestVerifiedId += processed; - if (latestL2Height > s.latestFinalizedHeight) { - s.latestFinalizedHeight = latestL2Height; + if (latestL2Height > s.latestVerifiedHeight) { + s.latestVerifiedHeight = latestL2Height; s.l2Hashes[latestL2Height] = latestL2Hash; emit HeaderSynced(block.number, latestL2Height, latestL2Hash); } diff --git a/packages/protocol/contracts/L1/v1/V1Proposing.sol b/packages/protocol/contracts/L1/v1/V1Proposing.sol index 8965ab41f6..6201aac38a 100644 --- a/packages/protocol/contracts/L1/v1/V1Proposing.sol +++ b/packages/protocol/contracts/L1/v1/V1Proposing.sol @@ -64,7 +64,7 @@ library V1Proposing { ); require( s.nextBlockId <= - s.latestFinalizedId + LibConstants.TAIKO_MAX_PROPOSED_BLOCKS, + s.latestVerifiedId + LibConstants.TAIKO_MAX_PROPOSED_BLOCKS, "L1:tooMany" ); diff --git a/packages/protocol/contracts/L1/v1/V1Proving.sol b/packages/protocol/contracts/L1/v1/V1Proving.sol index 0be26baf0e..046d01e9be 100644 --- a/packages/protocol/contracts/L1/v1/V1Proving.sol +++ b/packages/protocol/contracts/L1/v1/V1Proving.sol @@ -316,7 +316,7 @@ library V1Proving { LibData.BlockMetadata memory meta ) private view { require( - meta.id > s.latestFinalizedId && meta.id < s.nextBlockId, + meta.id > s.latestVerifiedId && meta.id < s.nextBlockId, "L1:meta:id" ); require( diff --git a/packages/protocol/contracts/L2/V1TaikoL2.sol b/packages/protocol/contracts/L2/V1TaikoL2.sol index f83e1b7a21..b087bd9d01 100644 --- a/packages/protocol/contracts/L2/V1TaikoL2.sol +++ b/packages/protocol/contracts/L2/V1TaikoL2.sol @@ -140,7 +140,7 @@ contract V1TaikoL2 is AddressResolver, ReentrancyGuard, IHeaderSync { returns ( uint256, // TAIKO_CHAIN_ID uint256, // TAIKO_MAX_PROPOSED_BLOCKS - uint256, // TAIKO_MAX_FINALIZATIONS_PER_TX + uint256, // TAIKO_MAX_VERIFICATIONS_PER_TX uint256, // TAIKO_COMMIT_DELAY_CONFIRMATIONS uint256, // TAIKO_MAX_PROOFS_PER_FORK_CHOICE uint256, // TAIKO_BLOCK_MAX_GAS_LIMIT @@ -156,7 +156,7 @@ contract V1TaikoL2 is AddressResolver, ReentrancyGuard, IHeaderSync { return ( LibConstants.TAIKO_CHAIN_ID, LibConstants.TAIKO_MAX_PROPOSED_BLOCKS, - LibConstants.TAIKO_MAX_FINALIZATIONS_PER_TX, + LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX, LibConstants.TAIKO_COMMIT_DELAY_CONFIRMATIONS, LibConstants.TAIKO_MAX_PROOFS_PER_FORK_CHOICE, LibConstants.TAIKO_BLOCK_MAX_GAS_LIMIT, diff --git a/packages/protocol/contracts/libs/LibConstants.sol b/packages/protocol/contracts/libs/LibConstants.sol index 870c512288..2fb3322f8b 100644 --- a/packages/protocol/contracts/libs/LibConstants.sol +++ b/packages/protocol/contracts/libs/LibConstants.sol @@ -13,7 +13,7 @@ library LibConstants { // https://github.com/ethereum-lists/chains/pull/1611 uint256 public constant TAIKO_CHAIN_ID = 167; uint256 public constant TAIKO_MAX_PROPOSED_BLOCKS = 2048; - uint256 public constant TAIKO_MAX_FINALIZATIONS_PER_TX = 20; + uint256 public constant TAIKO_MAX_VERIFICATIONS_PER_TX = 20; uint256 public constant TAIKO_COMMIT_DELAY_CONFIRMATIONS = 4; uint256 public constant TAIKO_MAX_PROOFS_PER_FORK_CHOICE = 5; uint256 public constant TAIKO_BLOCK_MAX_GAS_LIMIT = 5000000; // TODO diff --git a/packages/protocol/docs/L1/LibData.md b/packages/protocol/docs/L1/LibData.md index 561cb8225d..63f11bb57d 100644 --- a/packages/protocol/docs/L1/LibData.md +++ b/packages/protocol/docs/L1/LibData.md @@ -47,8 +47,8 @@ struct State { mapping(uint256 => mapping(bytes32 => struct LibData.ForkChoice)) forkChoices; mapping(bytes32 => uint256) commits; uint64 genesisHeight; - uint64 latestFinalizedHeight; - uint64 latestFinalizedId; + uint64 latestVerifiedHeight; + uint64 latestVerifiedId; uint64 nextBlockId; } ``` @@ -74,7 +74,7 @@ function getL2BlockHash(struct LibData.State s, uint256 number) internal view re ### getStateVariables ```solidity -function getStateVariables(struct LibData.State s) internal view returns (uint64 genesisHeight, uint64 latestFinalizedHeight, uint64 latestFinalizedId, uint64 nextBlockId) +function getStateVariables(struct LibData.State s) internal view returns (uint64 genesisHeight, uint64 latestVerifiedHeight, uint64 latestVerifiedId, uint64 nextBlockId) ``` ### hashMetadata diff --git a/packages/protocol/docs/L1/TaikoL1.md b/packages/protocol/docs/L1/TaikoL1.md index 099bfc209a..7e18387f85 100644 --- a/packages/protocol/docs/L1/TaikoL1.md +++ b/packages/protocol/docs/L1/TaikoL1.md @@ -80,19 +80,19 @@ merkel proof. | blockIndex | uint256 | The index of the block to prove. This is also used to select the right implementation version. | | inputs | bytes[] | A list of data input: - inputs[0] An Evidence object with various information regarding the block to be proven and the actual proofs. - inputs[1] The target block to be proven invalid. - inputs[2] The receipt for the `invalidBlock` transaction on L2. Note that the `invalidBlock` transaction is supposed to be the only transaction in the L2 block. | -### finalizeBlocks +### verifyBlocks ```solidity -function finalizeBlocks(uint256 maxBlocks) external +function verifyBlocks(uint256 maxBlocks) external ``` -Finalize up to N blocks. +Verify up to N blocks. #### Parameters -| Name | Type | Description | -| --------- | ------- | --------------------------------- | -| maxBlocks | uint256 | Max number of blocks to finalize. | +| Name | Type | Description | +| --------- | ------- | ------------------------------- | +| maxBlocks | uint256 | Max number of blocks to verify. | ### isCommitValid diff --git a/packages/protocol/docs/L1/v1/V1Events.md b/packages/protocol/docs/L1/v1/V1Events.md index 74dd5720cc..747fbddd77 100644 --- a/packages/protocol/docs/L1/v1/V1Events.md +++ b/packages/protocol/docs/L1/v1/V1Events.md @@ -1,9 +1,9 @@ ## V1Events -### BlockFinalized +### BlockVerified ```solidity -event BlockFinalized(uint256 id, bytes32 blockHash) +event BlockVerified(uint256 id, bytes32 blockHash) ``` ### BlockCommitted diff --git a/packages/protocol/docs/L1/v1/V1Finalizing.md b/packages/protocol/docs/L1/v1/V1Finalizing.md index 5d70700581..1dcf04bbe0 100644 --- a/packages/protocol/docs/L1/v1/V1Finalizing.md +++ b/packages/protocol/docs/L1/v1/V1Finalizing.md @@ -1,9 +1,9 @@ ## V1Finalizing -### BlockFinalized +### BlockVerified ```solidity -event BlockFinalized(uint256 id, bytes32 blockHash) +event BlockVerified(uint256 id, bytes32 blockHash) ``` ### HeaderSynced @@ -18,8 +18,8 @@ event HeaderSynced(uint256 height, uint256 srcHeight, bytes32 srcHash) function init(struct LibData.State s, bytes32 _genesisBlockHash) public ``` -### finalizeBlocks +### verifyBlocks ```solidity -function finalizeBlocks(struct LibData.State s, uint256 maxBlocks) public +function verifyBlocks(struct LibData.State s, uint256 maxBlocks) public ``` diff --git a/packages/protocol/docs/libs/LibConstants.md b/packages/protocol/docs/libs/LibConstants.md index d4f5831476..812205af2d 100644 --- a/packages/protocol/docs/libs/LibConstants.md +++ b/packages/protocol/docs/libs/LibConstants.md @@ -12,10 +12,10 @@ uint256 TAIKO_CHAIN_ID uint256 TAIKO_MAX_PROPOSED_BLOCKS ``` -### TAIKO_MAX_FINALIZATIONS_PER_TX +### TAIKO_MAX_VERIFICATIONS_PER_TX ```solidity -uint256 TAIKO_MAX_FINALIZATIONS_PER_TX +uint256 TAIKO_MAX_VERIFICATIONS_PER_TX ``` ### TAIKO_COMMIT_DELAY_CONFIRMATIONS diff --git a/packages/whitepaper/main.tex b/packages/whitepaper/main.tex index 4fce8cb244..0b8224c83d 100644 --- a/packages/whitepaper/main.tex +++ b/packages/whitepaper/main.tex @@ -134,8 +134,8 @@ \section{Overview}\label{sec:properties} We achieve this by splitting the block submission process in two parts: \begin{description} -\item[Block proposal] When a block gets proposed the block data is published on Ethereum and the block is appended to the proposed blocks list stored in the \underline{TaikoL1} contract. Once registered, the protocol ensures that \emph{all} block properties are immutable. This makes the block execution \emph{deterministic}: the post-block state can now be calculated by anyone. As such, the block is immediately \emph{finalized}. This also ensures that no one knows more about the latest state than anyone else, as that would create an unfair advantage. -\item[Block verification] Because the block should already be finalized once proposed, it should \emph{not} be possible for the prover to have any impact on how the block is executed and what the post-block state is. All relevant inputs for the proof generation are verified on L1 directly or indirectly to achieve deterministic block transitions. As all proposed blocks are deterministic, they can be proven in parallel, because all intermediate states between blocks are known and unique. Once a proof is submitted for the block and its parent block, we call the block \emph{on-chain finalized}. +\item[Block proposal] When a block gets proposed the block data is published on Ethereum and the block is appended to the proposed blocks list stored in the \underline{TaikoL1} contract. Once registered, the protocol ensures that \emph{all} block properties are immutable. This makes the block execution \emph{deterministic}: the post-block state can now be calculated by anyone. As such, the block is immediately \emph{verified}. This also ensures that no one knows more about the latest state than anyone else, as that would create an unfair advantage. +\item[Block verification] Because the block should already be verified once proposed, it should \emph{not} be possible for the prover to have any impact on how the block is executed and what the post-block state is. All relevant inputs for the proof generation are verified on L1 directly or indirectly to achieve deterministic block transitions. As all proposed blocks are deterministic, they can be proven in parallel, because all intermediate states between blocks are known and unique. Once a proof is submitted for the block and its parent block, we call the block \emph{on-chain verified}. \end{description} \section{The Taiko Blockchain} @@ -144,12 +144,12 @@ \section{The Taiko Blockchain} \subsection{Core Contracts} The Taiko ZK-Rollup protocol has two major smart contracts deployed on L1 and L2, respectively. -\subsubsection{TaikoL1} Deployed on Ethereum. This contract on L1 is used to propose, prove, and finalize L2 blocks. \underline{TaikoL1} maintains the following state variables: +\subsubsection{TaikoL1} Deployed on Ethereum. This contract on L1 is used to propose, prove, and verify L2 blocks. \underline{TaikoL1} maintains the following state variables: \begin{description} \item[numProposedBlocks] The total number of proposed blocks, and the ID for the next proposed block, formally $R_\mathrm{i}$. \item[proposedBlocks] The list of proposed blocks, formally $R_\mathrm{b}$. -\item[lastFinalizedBlockId] The ID of the last finalized block, formally $R_\mathrm{f}$. +\item[lastVerifiedBlockId] The ID of the last verified block, formally $R_\mathrm{f}$. \item [blockCommits] The mapping from the committed blocks' \emph{commit hashes} to their enclosed L1 blocks' block numbers, formally $R_\mathrm{c}$. If a block's commit hash is $h$, its number is $R_\mathrm{c}[h]$ (see Section \ref{sec:commit}). \item[forkChoices] The mapping from proposed block IDs to their \emph{Fork Choices}, formally $R_\mathrm{f}$. The fork choices for the $i$-th block is $R_\mathrm{f}[i]$. Fork Choices are discussed in detail in Section \ref{sec:proving}. \end{description} @@ -161,7 +161,7 @@ \subsubsection{{TaikoL2}} Deployed on Taiko. This contract on L2 allows us to re \end{enumerate} \subsection{Proposing Blocks} -Any willing entity can propose new Taiko blocks using the {\underline{TaikoL1}} contract. Blocks are appended to a list in the order they come in (which is dictated by Ethereum). Once the block is in the list it is finalized and nodes can apply its state to the latest L2 state (see Section \ref{sec:properties}). Certain blocks however are deemed invalid by the protocol and these blocks will be ignored (see Section \ref{sec:proving-invalid}). +Any willing entity can propose new Taiko blocks using the {\underline{TaikoL1}} contract. Blocks are appended to a list in the order they come in (which is dictated by Ethereum). Once the block is in the list it is verified and nodes can apply its state to the latest L2 state (see Section \ref{sec:properties}). Certain blocks however are deemed invalid by the protocol and these blocks will be ignored (see Section \ref{sec:proving-invalid}). \subsubsection{Proposed Block} A proposed block in Taiko is the collection of information (known as the block's \emph{Metadata}), $C$, and a list of transactions, $L$, (known as the block \emph{txList}). Formally, we can refer to a proposed block as $\dot{B}$: @@ -339,9 +339,9 @@ \subsubsection{Construction of Anchor Transactions} All anchor transactions are \subsection{Proving Blocks} \label{sec:proving} -A proof needs to be submitted to Ethereum so that a block can be on-chain finalized. We stress again that all proposed blocks are finalized immediately because proposed blocks are deterministic and cannot be reverted. The prover has \emph{no} impact on the post-block state. The proof is only required to prove to the \underline{TaikoL1} smart contract that the L2 state transitions and the rollup protocol rules are fully constrained. These on-chain verified L2 states are made accessible to other smart contracts (and indirectly to other L2s) so they can have access to the full L2 state, which is critical for e.g. bridges (see Section \ref{sec:bridges}). +A proof needs to be submitted to Ethereum so that a block can be on-chain verified. We stress again that all proposed blocks are verified immediately because proposed blocks are deterministic and cannot be reverted. The prover has \emph{no} impact on the post-block state. The proof is only required to prove to the \underline{TaikoL1} smart contract that the L2 state transitions and the rollup protocol rules are fully constrained. These on-chain verified L2 states are made accessible to other smart contracts (and indirectly to other L2s) so they can have access to the full L2 state, which is critical for e.g. bridges (see Section \ref{sec:bridges}). -Blocks can be proven in parallel and so proofs may be submitted out-of-order. As a result, when proofs are submitted for blocks where the parent block is not yet finalized, we cannot know if the proof is for the correct state transition. A proof on its own can only verify that the state transition from one state to another state is done correctly, not that the initial state is the correct one. As such, proving a block can create a Fork Choice which is an attestation that the block in question transits from a prover-selected parent block to a correctly calculated new world state. It is important to note that there is only a single valid fork choice per block: the fork choice that transitions from the last on-chain finalized block to the next \emph{valid} proposed block. All other fork choices use an incorrect pre-block state. +Blocks can be proven in parallel and so proofs may be submitted out-of-order. As a result, when proofs are submitted for blocks where the parent block is not yet verified, we cannot know if the proof is for the correct state transition. A proof on its own can only verify that the state transition from one state to another state is done correctly, not that the initial state is the correct one. As such, proving a block can create a Fork Choice which is an attestation that the block in question transits from a prover-selected parent block to a correctly calculated new world state. It is important to note that there is only a single valid fork choice per block: the fork choice that transitions from the last on-chain verified block to the next \emph{valid} proposed block. All other fork choices use an incorrect pre-block state. A Fork Choice is a tuple of 3 elements: @@ -351,7 +351,7 @@ \subsection{Proving Blocks} \label{sec:proving} where $H_p$ is the block's parent hash, $H_h \equiv \texttt{KEC}(\texttt{RLP}(H))$ is the hash of the proposed block, and $(a_i, p^{z}_i, [p^{m_1}_i,...])$ are the $i$-th prover's address and the proofs. $p^{z}$ is a proof that shows the state transition from the parent hash to the block hash is correct, and [$p^{m_1}$,...] are Merkle proofs in the storage, transaction, and/or receipt trie that prove the anchor transaction has been executed successfully as the first transaction of the L2 block. -Taiko accepts up to $K_{\mathrm{MaxProofsPerForkChoice}}$ proofs per fork choice. Proofs for the correct fork choice will be eligible for compensation. No limit is set on the number of fork choices as the protocol does not know which fork choice for a block is the correct one until the parent block is on-chain finalized. +Taiko accepts up to $K_{\mathrm{MaxProofsPerForkChoice}}$ proofs per fork choice. Proofs for the correct fork choice will be eligible for compensation. No limit is set on the number of fork choices as the protocol does not know which fork choice for a block is the correct one until the parent block is on-chain verified. \subsubsection{Invalid Blocks} \label{sec:proving-invalid} @@ -373,11 +373,11 @@ \subsubsection{Invalid Blocks} \label{sec:proving-invalid} It's important to note that these throw-away blocks are never a part of the Taiko chain. The only purpose of the block is to be able reuse the EVM proving subsystem so that we can create proofs for blocks with unexpected transaction data. -\subsection{On-chain Finalization of Blocks}\label{sec:finalizing} +\subsection{On-chain Finalization of Blocks}\label{sec:verifying} -Assuming the $j$-th block is the last finalized valid block. The $i$-th block ($i > j$) can be finalized if 1) the $(i-1)$-th block has been finalized, and 2) the $i$-th block has a Fork Choice $E$ whose parent block hash $E(H_p)$ equals the $j$-th block's hash. +Assuming the $j$-th block is the last verified valid block. The $i$-th block ($i > j$) can be verified if 1) the $(i-1)$-th block has been verified, and 2) the $i$-th block has a Fork Choice $E$ whose parent block hash $E(H_p)$ equals the $j$-th block's hash. -If $H_h$ equals $K_{\mathrm{BlockDeadEndHash}}$, the $i$-th block is marked as finalized but $j$ is not updated (otherwise $j$ changes to $i$ and so the $i$-th block would become the last finalized valid block while the block is not valid). So on L1, because each block needs to handled, valid or invalid, all blocks are part of the block chain through the Fork Choices. In Taiko nodes invalid blocks can be immediately dropped and are never part of Taiko's canonical chain. +If $H_h$ equals $K_{\mathrm{BlockDeadEndHash}}$, the $i$-th block is marked as verified but $j$ is not updated (otherwise $j$ changes to $i$ and so the $i$-th block would become the last verified valid block while the block is not valid). So on L1, because each block needs to handled, valid or invalid, all blocks are part of the block chain through the Fork Choices. In Taiko nodes invalid blocks can be immediately dropped and are never part of Taiko's canonical chain. \section{ZK-EVM Circuits} @@ -967,7 +967,7 @@ \section{Protocol Constants}\label{sec:constants1} \midrule $K_{\mathrm{ChainID}}$ & Taiko's chain ID. \\ $K_{\mathrm{MaxNumBlocks}}$ & The maximum number of slots for proposed blocks. \\ -$K_{\mathrm{MaxFinalizationsPerTx}}$ & The number of proven blocks that can be finalized when a new block is\\ +$K_{\mathrm{MaxVerificationsPerTx}}$ & The number of proven blocks that can be verified when a new block is\\ & proposed or a block is proven. \\ $K_{\mathrm{CommitDelayConfirms}}$ & The number of confirmations to wait for before a block can be proposed\\ & after its commit-hash has been written on Ethereum.\\