From 878964efca86967df5e58e17ed1a6e4f1165e571 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Tue, 5 Sep 2023 19:03:39 +0800 Subject: [PATCH] refactor(protocol): change state.transitions as a ring buffer (#14645) Co-authored-by: Daniel Wang Co-authored-by: David Co-authored-by: D <51912515+adaki2004@users.noreply.github.com> Co-authored-by: Brecht Devos --- packages/protocol/contracts/L1/TaikoData.sol | 20 +++-- .../protocol/contracts/L1/TaikoL1Base.sol | 21 +---- .../contracts/L1/libs/LibProposing.sol | 86 +++++++++---------- .../protocol/contracts/L1/libs/LibProving.sol | 42 ++++----- .../contracts/L1/libs/LibTaikoToken.sol | 20 +++++ .../protocol/contracts/L1/libs/LibUtils.sol | 41 ++++----- .../contracts/L1/libs/LibVerifying.sol | 74 +++++++--------- .../contracts/libs/LibBlockHeader.sol | 4 +- .../protocol/docs/how_taiko_proves_blocks.md | 16 ++-- packages/protocol/package.json | 2 - packages/protocol/test/L1/TaikoL1.t.sol | 4 +- packages/protocol/test/L1/TaikoL1Oracle.t.sol | 20 ++--- packages/protocol/test/L1/TaikoL1TestBase.sol | 4 +- .../protocol/test/misc/GasComparison.t.sol | 4 +- 14 files changed, 174 insertions(+), 184 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index c9d0328f608..a57abb34d2c 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -86,7 +86,7 @@ library TaikoData { /// @dev Struct representing input data for block metadata. struct BlockMetadataInput { bytes32 txListHash; - address beneficiary; + address proposer; uint24 txListByteStart; // byte-wise start index (inclusive) uint24 txListByteEnd; // byte-wise end index (exclusive) bool cacheTxListInfo; @@ -112,7 +112,7 @@ library TaikoData { uint24 txListByteStart; uint24 txListByteEnd; uint32 gasLimit; - address beneficiary; + address proposer; TaikoData.EthDeposit[] depositsProcessed; } @@ -147,7 +147,6 @@ library TaikoData { uint64 proposedAt; uint32 nextTransitionId; uint32 verifiedTransitionId; - uint16 proofWindow; } /// @dev Struct representing information about a transaction list. @@ -185,15 +184,22 @@ library TaikoData { /// @dev Struct holding the state variables for the {TaikoL1} contract. struct State { // Ring buffer for proposed blocks and a some recent verified blocks. - mapping(uint64 blockId_mode_blockRingBufferSize => Block) blocks; + mapping(uint64 blockId_mod_blockRingBufferSize => Block) blocks; + // Indexing to transition ids (ring buffer not possible) mapping( uint64 blockId => mapping(bytes32 parentHash => uint32 transitionId) ) transitionIds; - mapping(uint64 blockId => mapping(uint32 transitionId => Transition)) - transitions; + // Ring buffer for transitions + mapping( + uint64 blockId_mod_blockRingBufferSize + => mapping(uint32 transitionId => Transition) + ) transitions; + // txList cached info mapping(bytes32 txListHash => TxListInfo) txListInfo; - mapping(uint256 depositId_mode_ethDepositRingBufferSize => uint256) + // Ring buffer for Ether deposits + mapping(uint256 depositId_mod_ethDepositRingBufferSize => uint256) ethDeposits; + // In-protocol Taiko token balances mapping(address account => uint256 balance) taikoTokenBalances; SlotA slotA; // slot 7 SlotB slotB; // slot 8 diff --git a/packages/protocol/contracts/L1/TaikoL1Base.sol b/packages/protocol/contracts/L1/TaikoL1Base.sol index 5eeec2dc63c..612066ab5c1 100644 --- a/packages/protocol/contracts/L1/TaikoL1Base.sol +++ b/packages/protocol/contracts/L1/TaikoL1Base.sol @@ -223,14 +223,8 @@ abstract contract TaikoL1Base is override returns (bytes32) { - (bool found, TaikoData.Block storage blk) = LibUtils.getL2ChainData({ - state: state, - config: getConfig(), - blockId: blockId - }); - return found - ? state.transitions[blk.blockId][blk.verifiedTransitionId].blockHash - : bytes32(0); + return LibUtils.getVerifyingTransition(state, getConfig(), blockId) + .blockHash; } /// @inheritdoc ICrossChainSync @@ -240,15 +234,8 @@ abstract contract TaikoL1Base is override returns (bytes32) { - (bool found, TaikoData.Block storage blk) = LibUtils.getL2ChainData({ - state: state, - config: getConfig(), - blockId: blockId - }); - - return found - ? state.transitions[blockId][blk.verifiedTransitionId].signalRoot - : bytes32(0); + return LibUtils.getVerifyingTransition(state, getConfig(), blockId) + .signalRoot; } /// @notice Gets the state variables of the TaikoL1 contract. diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index b99886954b6..ae82509e057 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -15,6 +15,7 @@ import { IProver } from "../IProver.sol"; import { LibAddress } from "../../libs/LibAddress.sol"; import { LibDepositing } from "./LibDepositing.sol"; import { LibMath } from "../../libs/LibMath.sol"; +import { LibTaikoToken } from "./LibTaikoToken.sol"; import { LibUtils } from "./LibUtils.sol"; import { TaikoData } from "../TaikoData.sol"; import { TaikoToken } from "../TaikoToken.sol"; @@ -81,15 +82,12 @@ library LibProposing { revert L1_TOO_MANY_BLOCKS(); } - TaikoToken tt = TaikoToken(resolver.resolve("taiko_token", false)); - if (state.taikoTokenBalances[assignment.prover] >= config.proofBond) { - // Safe, see the above constraint - unchecked { - state.taikoTokenBalances[assignment.prover] -= config.proofBond; - } - } else { - tt.transferFrom(assignment.prover, address(this), config.proofBond); - } + TaikoToken tt = LibTaikoToken.receiveTaikoToken({ + state: state, + resolver: resolver, + from: assignment.prover, + amount: config.proofBond + }); // Pay prover after verifying assignment if (config.skipProverAssignmentVerificaiton) { @@ -144,7 +142,7 @@ library LibProposing { ); // Reward must be minted - tt.mint(input.beneficiary, reward); + tt.mint(input.proposer, reward); } } } @@ -178,9 +176,9 @@ library LibProposing { meta.txListByteStart = input.txListByteStart; meta.txListByteEnd = input.txListByteEnd; meta.gasLimit = config.blockMaxGasLimit; - meta.beneficiary = input.beneficiary; + meta.proposer = input.proposer; meta.depositsProcessed = - LibDepositing.processDeposits(state, config, input.beneficiary); + LibDepositing.processDeposits(state, config, input.proposer); // Init the block TaikoData.Block storage blk = @@ -193,7 +191,6 @@ library LibProposing { blk.proposedAt = meta.timestamp; blk.nextTransitionId = 1; blk.verifiedTransitionId = 0; - blk.proofWindow = config.proofWindow; emit BlockProposed({ blockId: state.slotB.numBlocks++, @@ -229,48 +226,47 @@ library LibProposing { view returns (bool cacheTxListInfo) { - if (input.beneficiary == address(0)) revert L1_INVALID_METADATA(); + if (input.proposer == address(0)) revert L1_INVALID_METADATA(); - uint64 timeNow = uint64(block.timestamp); // handling txList - { - uint24 size = uint24(txList.length); - if (size > config.blockMaxTxListBytes) revert L1_TX_LIST(); - if (input.txListByteStart > input.txListByteEnd) { + uint24 size = uint24(txList.length); + if (size > config.blockMaxTxListBytes) revert L1_TX_LIST(); + + if (input.txListByteStart > input.txListByteEnd) { + revert L1_TX_LIST_RANGE(); + } + + if (config.blockTxListExpiry == 0) { + // caching is disabled + if (input.txListByteStart != 0 || input.txListByteEnd != size) { revert L1_TX_LIST_RANGE(); } + } else { + // caching is enabled + if (size == 0) { + // This blob shall have been submitted earlier + TaikoData.TxListInfo memory info = + state.txListInfo[input.txListHash]; - if (config.blockTxListExpiry == 0) { - // caching is disabled - if (input.txListByteStart != 0 || input.txListByteEnd != size) { + if (input.txListByteEnd > info.size) { revert L1_TX_LIST_RANGE(); } - } else { - // caching is enabled - if (size == 0) { - // This blob shall have been submitted earlier - TaikoData.TxListInfo memory info = - state.txListInfo[input.txListHash]; - - if (input.txListByteEnd > info.size) { - revert L1_TX_LIST_RANGE(); - } - - if ( - info.size == 0 - || info.validSince + config.blockTxListExpiry < timeNow - ) { - revert L1_TX_LIST_NOT_EXIST(); - } - } else { - if (input.txListByteEnd > size) revert L1_TX_LIST_RANGE(); - if (input.txListHash != keccak256(txList)) { - revert L1_TX_LIST_HASH(); - } - cacheTxListInfo = input.cacheTxListInfo; + if ( + info.size == 0 + || info.validSince + config.blockTxListExpiry + < block.timestamp + ) { + revert L1_TX_LIST_NOT_EXIST(); } + } else { + if (input.txListByteEnd > size) revert L1_TX_LIST_RANGE(); + if (input.txListHash != keccak256(txList)) { + revert L1_TX_LIST_HASH(); + } + + cacheTxListInfo = input.cacheTxListInfo; } } } diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol index a8052604405..1619f2614a6 100644 --- a/packages/protocol/contracts/L1/libs/LibProving.sol +++ b/packages/protocol/contracts/L1/libs/LibProving.sol @@ -45,9 +45,7 @@ library LibProving { { if ( evidence.prover == address(0) || evidence.parentHash == 0 - || evidence.blockHash == 0 - || evidence.blockHash == evidence.parentHash - || evidence.signalRoot == 0 + || evidence.blockHash == 0 || evidence.signalRoot == 0 ) revert L1_INVALID_EVIDENCE(); TaikoData.SlotB memory b = state.slotB; @@ -55,8 +53,9 @@ library LibProving { revert L1_INVALID_BLOCK_ID(); } - TaikoData.Block storage blk = - state.blocks[blockId % config.blockRingBufferSize]; + uint64 slot = blockId % config.blockRingBufferSize; + TaikoData.Block storage blk = state.blocks[slot]; + if (blk.blockId != blockId) revert L1_BLOCK_ID_MISMATCH(); // Check the metadata hash matches the proposed block's. This is @@ -83,9 +82,10 @@ library LibProving { ) revert L1_NOT_PROVEABLE(); } - TaikoData.Transition storage tz; + TaikoData.Transition storage tran; + uint32 tid = - LibUtils.getTransitionId(state, blk, blockId, evidence.parentHash); + LibUtils.getTransitionId(state, blk, slot, evidence.parentHash); if (tid == 0) { tid = blk.nextTransitionId; @@ -97,11 +97,11 @@ library LibProving { ++blk.nextTransitionId; } - tz = state.transitions[blk.blockId][tid]; + tran = state.transitions[slot][tid]; if (tid == 1) { // We only write the key when tid is 1. - tz.key = evidence.parentHash; + tran.key = evidence.parentHash; } else { state.transitionIds[blk.blockId][evidence.parentHash] = tid; } @@ -109,19 +109,19 @@ library LibProving { // This is the branch the oracle prover is trying to overwrite // We need to check the previous proof is not the same as the // new proof - tz = state.transitions[blk.blockId][tid]; + tran = state.transitions[slot][tid]; if ( - tz.blockHash == evidence.blockHash - && tz.signalRoot == evidence.signalRoot + tran.blockHash == evidence.blockHash + && tran.signalRoot == evidence.signalRoot ) revert L1_SAME_PROOF(); } else { revert L1_ALREADY_PROVEN(); } - tz.blockHash = evidence.blockHash; - tz.signalRoot = evidence.signalRoot; - tz.prover = evidence.prover; - tz.provenAt = uint64(block.timestamp); + tran.blockHash = evidence.blockHash; + tran.signalRoot = evidence.signalRoot; + tran.prover = evidence.prover; + tran.provenAt = uint64(block.timestamp); IProofVerifier(resolver.resolve("proof_verifier", false)).verifyProofs( blockId, evidence.proofs, getInstance(evidence) @@ -144,21 +144,21 @@ library LibProving { ) internal view - returns (TaikoData.Transition storage tz) + returns (TaikoData.Transition storage tran) { TaikoData.SlotB memory b = state.slotB; if (blockId < b.lastVerifiedBlockId || blockId >= b.numBlocks) { revert L1_INVALID_BLOCK_ID(); } - TaikoData.Block storage blk = - state.blocks[blockId % config.blockRingBufferSize]; + uint64 slot = blockId % config.blockRingBufferSize; + TaikoData.Block storage blk = state.blocks[slot]; if (blk.blockId != blockId) revert L1_BLOCK_ID_MISMATCH(); - uint32 tid = LibUtils.getTransitionId(state, blk, blockId, parentHash); + uint32 tid = LibUtils.getTransitionId(state, blk, slot, parentHash); if (tid == 0) revert L1_TRANSITION_NOT_FOUND(); - tz = state.transitions[blockId][tid]; + tran = state.transitions[slot][tid]; } function getInstance(TaikoData.BlockEvidence memory evidence) diff --git a/packages/protocol/contracts/L1/libs/LibTaikoToken.sol b/packages/protocol/contracts/L1/libs/LibTaikoToken.sol index 047136d804e..3b4ca51f998 100644 --- a/packages/protocol/contracts/L1/libs/LibTaikoToken.sol +++ b/packages/protocol/contracts/L1/libs/LibTaikoToken.sol @@ -49,4 +49,24 @@ library LibTaikoToken { state.taikoTokenBalances[msg.sender] += amount; } } + + function receiveTaikoToken( + TaikoData.State storage state, + AddressResolver resolver, + address from, + uint256 amount + ) + internal + returns (TaikoToken tt) + { + tt = TaikoToken(resolver.resolve("taiko_token", false)); + if (state.taikoTokenBalances[from] >= amount) { + // Safe, see the above constraint + unchecked { + state.taikoTokenBalances[from] -= amount; + } + } else { + tt.transferFrom(from, address(this), amount); + } + } } diff --git a/packages/protocol/contracts/L1/libs/LibUtils.sol b/packages/protocol/contracts/L1/libs/LibUtils.sol index c573228fd8c..db5f4ffc447 100644 --- a/packages/protocol/contracts/L1/libs/LibUtils.sol +++ b/packages/protocol/contracts/L1/libs/LibUtils.sol @@ -17,39 +17,40 @@ library LibUtils { error L1_INVALID_BLOCK_ID(); - function getL2ChainData( + function getTransitionId( TaikoData.State storage state, - TaikoData.Config memory config, - uint64 blockId + TaikoData.Block storage blk, + uint64 slot, + bytes32 parentHash ) internal view - returns (bool found, TaikoData.Block storage blk) + returns (uint32 tid) { - uint64 id = blockId == 0 ? state.slotB.lastVerifiedBlockId : blockId; + if (state.transitions[slot][1].key == parentHash) { + tid = 1; + } else { + tid = state.transitionIds[blk.blockId][parentHash]; + } - blk = state.blocks[id % config.blockRingBufferSize]; - found = blk.blockId == id; + assert(tid < blk.nextTransitionId); } - function getTransitionId( + function getVerifyingTransition( TaikoData.State storage state, - TaikoData.Block storage blk, - uint64 blockId, - bytes32 parentHash + TaikoData.Config memory config, + uint64 blockId ) internal view - returns (uint32 tid) + returns (TaikoData.Transition memory transition) { - if (state.transitions[blk.blockId][1].key == parentHash) { - tid = 1; - } else { - tid = state.transitionIds[blockId][parentHash]; - } + uint64 id = blockId == 0 ? state.slotB.lastVerifiedBlockId : blockId; + uint64 slot = id % config.blockRingBufferSize; - if (tid >= blk.nextTransitionId) { - tid = 0; + TaikoData.Block storage blk = state.blocks[slot]; + if (blk.blockId == id) { + transition = state.transitions[slot][blk.verifiedTransitionId]; } } @@ -91,7 +92,7 @@ library LibUtils { inputs[5] = (uint256(meta.txListByteStart) << 232) | (uint256(meta.txListByteEnd) << 208) // | (uint256(meta.gasLimit) << 176) - | (uint256(uint160(meta.beneficiary)) << 16); + | (uint256(uint160(meta.proposer)) << 16); assembly { hash := keccak256(inputs, mul(6, 32)) diff --git a/packages/protocol/contracts/L1/libs/LibVerifying.sol b/packages/protocol/contracts/L1/libs/LibVerifying.sol index 11f453ce8a3..053d257f1f6 100644 --- a/packages/protocol/contracts/L1/libs/LibVerifying.sol +++ b/packages/protocol/contracts/L1/libs/LibVerifying.sol @@ -14,7 +14,6 @@ import { ISignalService } from "../../signal/ISignalService.sol"; import { LibMath } from "../../libs/LibMath.sol"; import { LibUtils } from "./LibUtils.sol"; import { TaikoData } from "../../L1/TaikoData.sol"; -import { TaikoToken } from "../TaikoToken.sol"; library LibVerifying { using Address for address; @@ -62,30 +61,22 @@ library LibVerifying { >= type(uint96).max / config.ethDepositMaxCountPerBlock ) revert L1_INVALID_CONFIG(); - // Unchecked is safe: - // - assignment is within ranges - // - block.timestamp will still be within uint64 range for the next - // 500K+ years. - unchecked { - uint64 timeNow = uint64(block.timestamp); - - // Init state - state.slotA.genesisHeight = uint64(block.number); - state.slotA.genesisTimestamp = timeNow; - state.slotB.numBlocks = 1; - state.slotB.lastVerifiedAt = uint64(block.timestamp); - - // Init the genesis block - TaikoData.Block storage blk = state.blocks[0]; - blk.nextTransitionId = 2; - blk.verifiedTransitionId = 1; - blk.proposedAt = timeNow; - - // Init the first state transition - TaikoData.Transition storage tz = state.transitions[0][1]; - tz.blockHash = genesisBlockHash; - tz.provenAt = timeNow; - } + // Init state + state.slotA.genesisHeight = uint64(block.number); + state.slotA.genesisTimestamp = uint64(block.timestamp); + state.slotB.numBlocks = 1; + state.slotB.lastVerifiedAt = uint64(block.timestamp); + + // Init the genesis block + TaikoData.Block storage blk = state.blocks[0]; + blk.nextTransitionId = 2; + blk.verifiedTransitionId = 1; + blk.proposedAt = uint64(block.timestamp); + + // Init the first state transition + TaikoData.Transition storage tran = state.transitions[0][1]; + tran.blockHash = genesisBlockHash; + tran.provenAt = uint64(block.timestamp); emit BlockVerified({ blockId: 0, @@ -105,17 +96,17 @@ library LibVerifying { TaikoData.SlotB memory b = state.slotB; uint64 blockId = b.lastVerifiedBlockId; - TaikoData.Block storage blk = - state.blocks[blockId % config.blockRingBufferSize]; + uint64 slot = blockId % config.blockRingBufferSize; + TaikoData.Block storage blk = state.blocks[slot]; if (blk.blockId != blockId) revert L1_BLOCK_ID_MISMATCH(); uint32 tid = blk.verifiedTransitionId; if (tid == 0) revert L1_UNEXPECTED_TRANSITION_ID(); - bytes32 blockHash = state.transitions[blockId][tid].blockHash; + bytes32 blockHash = state.transitions[slot][tid].blockHash; bytes32 signalRoot; - TaikoData.Transition memory tz; + TaikoData.Transition storage tran; uint64 processed; @@ -127,38 +118,39 @@ library LibVerifying { ++blockId; while (blockId < b.numBlocks && processed < maxBlocks) { - blk = state.blocks[blockId % config.blockRingBufferSize]; + slot = blockId % config.blockRingBufferSize; + blk = state.blocks[slot]; if (blk.blockId != blockId) revert L1_BLOCK_ID_MISMATCH(); - tid = LibUtils.getTransitionId(state, blk, blockId, blockHash); + tid = LibUtils.getTransitionId(state, blk, slot, blockHash); if (tid == 0) break; - tz = state.transitions[blockId][tid]; - if (tz.prover == address(0)) break; + tran = state.transitions[slot][tid]; + if (tran.prover == address(0)) break; - uint256 proofCooldown = tz.prover == LibUtils.ORACLE_PROVER + uint256 proofCooldown = tran.prover == LibUtils.ORACLE_PROVER ? config.proofOracleCooldown : config.proofRegularCooldown; - if (block.timestamp <= tz.provenAt + proofCooldown) { + if (block.timestamp <= tran.provenAt + proofCooldown) { break; } - blockHash = tz.blockHash; - signalRoot = tz.signalRoot; + blockHash = tran.blockHash; + signalRoot = tran.signalRoot; blk.verifiedTransitionId = tid; // Refund bond or give 1/4 of it to the actual prover and burn // the rest. if ( - tz.prover == LibUtils.ORACLE_PROVER - || tz.provenAt <= blk.proposedAt + blk.proofWindow + tran.prover == LibUtils.ORACLE_PROVER + || tran.provenAt <= blk.proposedAt + config.proofWindow ) { state.taikoTokenBalances[blk.prover] += blk.proofBond; } else { - state.taikoTokenBalances[tz.prover] += blk.proofBond / 4; + state.taikoTokenBalances[tran.prover] += blk.proofBond / 4; } - emit BlockVerified(blockId, tz.prover, tz.blockHash); + emit BlockVerified(blockId, tran.prover, tran.blockHash); ++blockId; ++processed; diff --git a/packages/protocol/contracts/libs/LibBlockHeader.sol b/packages/protocol/contracts/libs/LibBlockHeader.sol index b6d6b92c8fa..c2becfd739c 100644 --- a/packages/protocol/contracts/libs/LibBlockHeader.sol +++ b/packages/protocol/contracts/libs/LibBlockHeader.sol @@ -12,7 +12,7 @@ import { LibRLPWriter } from "../thirdparty/LibRLPWriter.sol"; struct BlockHeader { bytes32 parentHash; bytes32 ommersHash; - address beneficiary; + address proposer; bytes32 stateRoot; bytes32 transactionsRoot; bytes32 receiptsRoot; @@ -69,7 +69,7 @@ library LibBlockHeader { } list[0] = LibRLPWriter.writeHash(header.parentHash); list[1] = LibRLPWriter.writeHash(header.ommersHash); - list[2] = LibRLPWriter.writeAddress(header.beneficiary); + list[2] = LibRLPWriter.writeAddress(header.proposer); list[3] = LibRLPWriter.writeHash(header.stateRoot); list[4] = LibRLPWriter.writeHash(header.transactionsRoot); list[5] = LibRLPWriter.writeHash(header.receiptsRoot); diff --git a/packages/protocol/docs/how_taiko_proves_blocks.md b/packages/protocol/docs/how_taiko_proves_blocks.md index c638b349e2e..ae7d5e873b0 100644 --- a/packages/protocol/docs/how_taiko_proves_blocks.md +++ b/packages/protocol/docs/how_taiko_proves_blocks.md @@ -85,7 +85,7 @@ struct BlockMetadata { uint24 txListByteStart; uint24 txListByteEnd; uint32 gasLimit; - address beneficiary; + address proposer; address treasury; TaikoData.EthDeposit[] depositsProcessed; } @@ -100,7 +100,7 @@ struct BlockMetadata { - `txListByteStart`: Byte start of the transaction list in L2. - `txListByteEnd`: Byte end of the transaction list in L2. - `gasLimit`: Gas limit for the L2 block. -- `beneficiary`: The address of the beneficiary in L2. +- `proposer`: The address of the proposer in L2. - `treasury`: The address where the base fee goes in L2. - `depositsProcessed`: The initiated L1->L2 Ether deposits that make up the depositRoot. @@ -125,7 +125,7 @@ We need to verify when these variables are accessed within the EVM, their values - The other 255 hashes, `blockhash(block.number - 256)` to `blockhash(block.number - 2)` are checked in the anchor transaction to simplify circuits. Therefore, as long as the anchor transaction is zk-proven, these 255 ancestor hashes are proven indirectly. - `block.basefee`: verified to be the correct value in the anchor transaction. - `block.chainid`: this field is also checked by the anchor transaction, so no extra ZKP circuits are required. -- `block.coinbase`: ZKP must verify the value must be the same as `meta.beneficiary`. Again, the metadata hash is part of the ZK instance. +- `block.coinbase`: ZKP must verify the value must be the same as `meta.proposer`. Again, the metadata hash is part of the ZK instance. - `block.prevrandao`: this is now the same as `block.prevrandao`, so we only check `block.prevrandao`. - `block.gaslimit`: ZKP must verify this value must equal `meta.gasLimit`. - `block.number`: this must be checked against the block header and `meta.id`. @@ -140,7 +140,7 @@ Not all block header data is available in the L1 contracts; therefore, the ZKP m struct BlockHeader { bytes32 parentHash; bytes32 ommersHash; - address beneficiary; + address proposer; bytes32 stateRoot; bytes32 transactionsRoot; bytes32 receiptsRoot; @@ -162,7 +162,7 @@ In addition, ZKP must also prove the following: - `parentHash` must be the same as `evidence.parentHash`. - `ommersHash` must be the keccak256 of `[]`,or `0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347`. -- `beneficiary` must be `meta.beneficiary` (duplicated, as stated above). +- `proposer` must be `meta.proposer` (duplicated, as stated above). - `logsBloom` must be a `bytes32[8]` with all zeros. - `difficulty` == 0. - `height` must be `meta.id`. @@ -214,7 +214,7 @@ m_txlist_first ---|<=| m_txlist_last --- |<= len| tx_list; m_h1_hash --- a_l1_hash; m_mix_hash --- h_mix_hash --- v_block_prevrando; tx_list -.->|keccak| m_txlist_hash; -m_beneficiary --- h_beneficiary; +m_proposer --- h_proposer; h_parent_hash --- v_blockhash_1 & e_parent_hash; l2_treasury -.-> m_treasury; @@ -261,7 +261,7 @@ m_txlist_hash(txListHash) m_txlist_first(txListByteStart) m_txlist_last(txListByteEnd) m_treasury(treasury) -m_beneficiary(beneficiary) +m_proposer(proposer) l2_treasury("L2 basefee goes to treasury"):::constant; tx_list("txList\n(blob or calldata)"):::constant; m_processed_deposits("ethDepositsProcessed"):::constant @@ -277,7 +277,7 @@ h_gas_limit(gasLimit) h_gas_used(gasUsed) h_timestamp(timestamp) h_mix_hash(mixHash) -h_beneficiary(beneficiary) +h_proposer(proposer) h_parent_hash(parentHash) h_ommers_hash("ommersHash = keccak([])") h_state_root(stateRoot) diff --git a/packages/protocol/package.json b/packages/protocol/package.json index ece76e9ecd0..03a6830526f 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -14,8 +14,6 @@ "fmt:sol": "forge fmt", "generate:genesis": "ts-node ./utils/generate_genesis/main.ts", "lint:sol": "forge fmt && pnpm solhint 'contracts/**/*.sol' --fix", - "sim": "forge test -vvv --gas-report --fuzz-seed $(date +%s) --mp test/L1/TaikoL1.sim.sol --block-gas-limit 3000000000000000000", - "sim:export": "pnpm test:sim > simulation/exports/simulation_data_$(date +%s).txt", "sizer": "pnpm hardhat size-contracts", "snapshot": "forge snapshot --match-path 'test/**/*.t.sol'", "test": "forge test -vvv --gas-report --fuzz-seed $(date +%s) --nmp test/L1/TaikoL1.sim.sol", diff --git a/packages/protocol/test/L1/TaikoL1.t.sol b/packages/protocol/test/L1/TaikoL1.t.sol index 97b38247ceb..537b00ff77e 100644 --- a/packages/protocol/test/L1/TaikoL1.t.sol +++ b/packages/protocol/test/L1/TaikoL1.t.sol @@ -66,9 +66,7 @@ contract TaikoL1Test is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint256 blockId = 1; - blockId < conf.blockMaxProposals * 10; - blockId++ + uint256 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { //printVariables("before propose"); TaikoData.BlockMetadata memory meta = diff --git a/packages/protocol/test/L1/TaikoL1Oracle.t.sol b/packages/protocol/test/L1/TaikoL1Oracle.t.sol index cc8b660aa4c..44cc9df379d 100644 --- a/packages/protocol/test/L1/TaikoL1Oracle.t.sol +++ b/packages/protocol/test/L1/TaikoL1Oracle.t.sol @@ -67,7 +67,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint256 blockId = 1; blockId < conf.blockMaxProposals * 9; blockId++ + uint256 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { printVariables("before propose"); TaikoData.BlockMetadata memory meta = @@ -120,9 +120,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint256 blockId = 1; - blockId < conf.blockMaxProposals * 10; - blockId++ + uint256 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { printVariables("before propose"); TaikoData.BlockMetadata memory meta = @@ -191,9 +189,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint256 blockId = 1; - blockId < conf.blockMaxProposals * 10; - blockId++ + uint256 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { TaikoData.BlockMetadata memory meta = proposeBlock(Alice, Bob, 1_000_000, 1024); @@ -252,9 +248,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint256 blockId = 1; - blockId < conf.blockMaxProposals * 10; - blockId++ + uint256 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { TaikoData.BlockMetadata memory meta = proposeBlock(Alice, Bob, 1_000_000, 1024); @@ -307,7 +301,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint64 blockId = 1; blockId < conf.blockMaxProposals * 10; blockId++ + uint64 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { TaikoData.BlockMetadata memory meta = proposeBlock(Alice, Bob, 1_000_000, 1024); @@ -380,9 +374,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 parentHash = GENESIS_BLOCK_HASH; for ( - uint256 blockId = 1; - blockId < conf.blockMaxProposals * 10; - blockId++ + uint256 blockId = 1; blockId < conf.blockMaxProposals * 3; blockId++ ) { TaikoData.BlockMetadata memory meta = proposeBlock(Alice, Bob, 1_000_000, 1024); diff --git a/packages/protocol/test/L1/TaikoL1TestBase.sol b/packages/protocol/test/L1/TaikoL1TestBase.sol index 1632d2f639c..ecd81e5bb6d 100644 --- a/packages/protocol/test/L1/TaikoL1TestBase.sol +++ b/packages/protocol/test/L1/TaikoL1TestBase.sol @@ -113,7 +113,7 @@ abstract contract TaikoL1TestBase is TestBase { bytes memory txList = new bytes(txListSize); TaikoData.BlockMetadataInput memory input = TaikoData.BlockMetadataInput({ - beneficiary: proposer, + proposer: proposer, txListHash: keccak256(txList), txListByteStart: 0, txListByteEnd: txListSize, @@ -136,7 +136,7 @@ abstract contract TaikoL1TestBase is TestBase { meta.txListByteStart = 0; meta.txListByteEnd = txListSize; meta.gasLimit = gasLimit; - meta.beneficiary = proposer; + meta.proposer = proposer; vm.prank(proposer, proposer); meta = diff --git a/packages/protocol/test/misc/GasComparison.t.sol b/packages/protocol/test/misc/GasComparison.t.sol index 57fed5148b6..f6a8d455986 100644 --- a/packages/protocol/test/misc/GasComparison.t.sol +++ b/packages/protocol/test/misc/GasComparison.t.sol @@ -80,7 +80,7 @@ contract FooBar { id: 1, l1Height: 1, l1Hash: bytes32(uint256(1)), - beneficiary: address(this), + proposer: address(this), txListHash: bytes32(uint256(1)), txListByteStart: 0, txListByteEnd: 1000, @@ -96,7 +96,7 @@ contract FooBar { id: 1, l1Height: 1, l1Hash: bytes32(uint256(1)), - beneficiary: address(this), + proposer: address(this), txListHash: bytes32(uint256(1)), txListByteStart: 0, txListByteEnd: 1000,