Skip to content

Commit

Permalink
refactor(protocol): extract two anchor-related functions (#13199)
Browse files Browse the repository at this point in the history
  • Loading branch information
dantaik authored Feb 22, 2023
1 parent ac068be commit 9c3fb10
Show file tree
Hide file tree
Showing 48 changed files with 236 additions and 241 deletions.
2 changes: 1 addition & 1 deletion packages/protocol/.solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"avoid-low-level-calls": "off",
"compiler-version": ["error", "^0.8.18"],
"func-visibility": ["warn", { "ignoreConstructors": true }],
"max-line-length": ["warn", 80],
"max-line-length": ["warn", 100],
"no-empty-blocks": "off",
"no-inline-assembly": "off",
"not-rely-on-time": "off",
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/ProofVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {EssentialContract} from "../common/EssentialContract.sol";
import {LibZKP} from "../libs/LibZKP.sol";
import {LibMerkleTrie} from "../thirdparty/LibMerkleTrie.sol";

/// @author dantaik <dan@taiko.xyz>
interface IProofVerifier {
function verifyZKP(
string memory verifierId,
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/L1/TaikoCustomErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

pragma solidity ^0.8.18;

/// @author david <david@taiko.xyz>
abstract contract TaikoCustomErrors {
// The following custom errors must match the definitions in other V1 libraries.
error L1_0_FEE_BASE();
Expand All @@ -21,6 +20,7 @@ abstract contract TaikoCustomErrors {
error L1_ANCHOR_RECEIPT_TOPICS();
error L1_ANCHOR_SIG_R();
error L1_ANCHOR_SIG_S();
error L1_ANCHOR_TX_PROOF();
error L1_ANCHOR_TYPE();
error L1_BLOCK_NUMBER();
error L1_CANNOT_BE_FIRST_PROVER();
Expand Down
5 changes: 3 additions & 2 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

pragma solidity ^0.8.18;

/// @author dantaik <dan@taiko.xyz>
library TaikoData {
struct Config {
uint256 chainId;
Expand Down Expand Up @@ -41,7 +40,7 @@ library TaikoData {
uint64 proverRewardRandomizedPercentage;
bool enableTokenomics;
bool enablePublicInputsCheck;
bool enableProofValidation;
bool enableAnchorValidation;
bool enableOracleProver;
}

Expand Down Expand Up @@ -80,7 +79,9 @@ library TaikoData {
// only the latest one if verified in a batch
mapping(uint256 blockId => bytes32 blockHash) l2Hashes;
mapping(uint256 blockId => ProposedBlock proposedBlock) proposedBlocks;
// solhint-disable-next-line max-line-length
mapping(uint256 blockId => mapping(bytes32 parentHash => ForkChoice forkChoice)) forkChoices;
// solhint-disable-next-line max-line-length
mapping(address proposerAddress => mapping(uint256 commitSlot => bytes32 commitHash)) commits;
// Never or rarely changed
uint64 genesisHeight;
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/TaikoEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ pragma solidity ^0.8.18;

import {TaikoData} from "./TaikoData.sol";

/// @author david <david@taiko.xyz>
abstract contract TaikoEvents {
// The following events must match the definitions in other V1 libraries.
event BlockVerified(uint256 indexed id, bytes32 blockHash);
Expand Down
3 changes: 0 additions & 3 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ import {LibUtils} from "./libs/LibUtils.sol";
import {LibVerifying} from "./libs/LibVerifying.sol";
import {AddressResolver} from "../common/AddressResolver.sol";

/**
* @author dantaik <dan@taiko.xyz>
*/
contract TaikoL1 is
EssentialContract,
IHeaderSync,
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/TkoToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
IERC20Upgradeable
} from "../thirdparty/ERC20Upgradeable.sol";

/// @author dantaik <dan@taiko.xyz>
/// @dev This is Taiko's governance and fee token.
contract TkoToken is EssentialContract, ERC20Upgradeable, IMintableERC20 {
using LibMath for uint256;
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/libs/LibProposing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {LibUtils} from "./LibUtils.sol";
import {TaikoData} from "../TaikoData.sol";
import {AddressResolver} from "../../common/AddressResolver.sol";

/// @author dantaik <dan@taiko.xyz>
library LibProposing {
using LibTxDecoder for bytes;
using SafeCastUpgradeable for uint256;
Expand Down
200 changes: 110 additions & 90 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import {LibRLPWriter} from "../../thirdparty/LibRLPWriter.sol";
import {LibUtils} from "./LibUtils.sol";
import {TaikoData} from "../../L1/TaikoData.sol";

/// @author dantaik <dan@taiko.xyz>
/// @author david <david@taiko.xyz>
library LibProving {
using LibBlockHeader for BlockHeader;
using LibUtils for TaikoData.BlockMetadata;
Expand Down Expand Up @@ -74,6 +72,7 @@ library LibProving {
error L1_ANCHOR_RECEIPT_ADDR();
error L1_ANCHOR_RECEIPT_TOPICS();
error L1_ANCHOR_RECEIPT_DATA();
error L1_ANCHOR_TX_PROOF();
error L1_HALTED();

function proveBlock(
Expand All @@ -89,9 +88,6 @@ library LibProving {
if (inputs.length != 3) revert L1_INPUT_SIZE();
Evidence memory evidence = abi.decode(inputs[0], (Evidence));

bytes calldata anchorTx = inputs[1];
bytes calldata anchorReceipt = inputs[2];

// Check evidence
if (evidence.meta.id != blockId) revert L1_ID();

Expand All @@ -106,59 +102,15 @@ library LibProving {
resolver.resolve("proof_verifier", false)
);

if (config.enableProofValidation) {
// Check anchor tx is valid
LibTxDecoder.Tx memory _tx = LibTxDecoder.decodeTx(
config.chainId,
anchorTx
);
if (_tx.txType != 0) revert L1_ANCHOR_TYPE();
if (
_tx.destination !=
resolver.resolve(config.chainId, "taiko", false)
) revert L1_ANCHOR_DEST();
if (_tx.gasLimit != config.anchorTxGasLimit)
revert L1_ANCHOR_GAS_LIMIT();

// Check anchor tx's signature is valid and deterministic
_validateAnchorTxSignature(config.chainId, _tx);

// Check anchor tx's calldata is valid
if (
!LibBytesUtils.equal(
_tx.data,
bytes.concat(
ANCHOR_TX_SELECTOR,
bytes32(evidence.meta.l1Height),
evidence.meta.l1Hash
)
)
) revert L1_ANCHOR_CALLDATA();

// Check anchor tx is the 1st tx in the block
if (
!proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: anchorTx,
proof: evidence.proofs[zkProofsPerBlock],
root: evidence.header.transactionsRoot
})
) revert L1_ZKP();

// Check anchor tx does not throw

LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(anchorReceipt);

if (receipt.status != 1) revert L1_ANCHOR_RECEIPT_STATUS();
if (
!proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: anchorReceipt,
proof: evidence.proofs[zkProofsPerBlock + 1],
root: evidence.header.receiptsRoot
})
) revert L1_ANCHOR_RECEIPT_PROOF();
if (config.enableAnchorValidation) {
_proveAnchorForValidBlock({
config: config,
resolver: resolver,
proofVerifier: proofVerifier,
evidence: evidence,
anchorTx: inputs[1],
anchorReceipt: inputs[2]
});
}

// ZK-prove block and mark block proven to be valid.
Expand Down Expand Up @@ -189,7 +141,6 @@ library LibProving {
inputs[1],
(TaikoData.BlockMetadata)
);
bytes calldata invalidateBlockReceipt = inputs[2];

// Check evidence
if (evidence.meta.id != blockId) revert L1_ID();
Expand All @@ -200,37 +151,15 @@ library LibProving {
resolver.resolve("proof_verifier", false)
);

// Check the event is the first one in the throw-away block
if (
!proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: invalidateBlockReceipt,
proof: evidence.proofs[config.zkProofsPerBlock],
root: evidence.header.receiptsRoot
})
) revert L1_ANCHOR_RECEIPT_PROOF();

// Check the 1st receipt is for an InvalidateBlock tx with
// a BlockInvalidated event
LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(invalidateBlockReceipt);
if (receipt.status != 1) revert L1_ANCHOR_RECEIPT_STATUS();

if (receipt.logs.length != 1) revert L1_ANCHOR_RECEIPT_LOGS();

{
LibReceiptDecoder.Log memory log = receipt.logs[0];
if (
log.contractAddress !=
resolver.resolve(config.chainId, "taiko", false)
) revert L1_ANCHOR_RECEIPT_ADDR();

if (log.data.length != 0) revert L1_ANCHOR_RECEIPT_DATA();
if (
log.topics.length != 2 ||
log.topics[0] != INVALIDATE_BLOCK_LOG_TOPIC ||
log.topics[1] != target.txListHash
) revert L1_ANCHOR_RECEIPT_TOPICS();
if (config.enableAnchorValidation) {
_proveAnchorForInvalidBlock({
config: config,
resolver: resolver,
target: target,
proofVerifier: proofVerifier,
evidence: evidence,
invalidateBlockReceipt: inputs[2]
});
}

// ZK-prove block and mark block proven as invalid.
Expand Down Expand Up @@ -393,6 +322,97 @@ library LibProving {
});
}

function _proveAnchorForValidBlock(
TaikoData.Config memory config,
AddressResolver resolver,
IProofVerifier proofVerifier,
Evidence memory evidence,
bytes calldata anchorTx,
bytes calldata anchorReceipt
) private view {
// Check anchor tx is valid
LibTxDecoder.Tx memory _tx = LibTxDecoder.decodeTx(
config.chainId,
anchorTx
);
if (_tx.txType != 0) revert L1_ANCHOR_TYPE();
if (_tx.destination != resolver.resolve(config.chainId, "taiko", false))
revert L1_ANCHOR_DEST();
if (_tx.gasLimit != config.anchorTxGasLimit)
revert L1_ANCHOR_GAS_LIMIT();
// Check anchor tx's signature is valid and deterministic
_validateAnchorTxSignature(config.chainId, _tx);
// Check anchor tx's calldata is valid
if (
!LibBytesUtils.equal(
_tx.data,
bytes.concat(
ANCHOR_TX_SELECTOR,
bytes32(evidence.meta.l1Height),
evidence.meta.l1Hash
)
)
) revert L1_ANCHOR_CALLDATA();
// Check anchor tx is the 1st tx in the block

uint256 zkProofsPerBlock = config.zkProofsPerBlock;
if (
!proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: anchorTx,
proof: evidence.proofs[zkProofsPerBlock],
root: evidence.header.transactionsRoot
})
) revert L1_ANCHOR_TX_PROOF();
// Check anchor tx does not throw
LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(anchorReceipt);
if (receipt.status != 1) revert L1_ANCHOR_RECEIPT_STATUS();
if (
!proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: anchorReceipt,
proof: evidence.proofs[zkProofsPerBlock + 1],
root: evidence.header.receiptsRoot
})
) revert L1_ANCHOR_RECEIPT_PROOF();
}

function _proveAnchorForInvalidBlock(
TaikoData.Config memory config,
AddressResolver resolver,
TaikoData.BlockMetadata memory target,
IProofVerifier proofVerifier,
Evidence memory evidence,
bytes calldata invalidateBlockReceipt
) private view {
if (
!proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: invalidateBlockReceipt,
proof: evidence.proofs[config.zkProofsPerBlock],
root: evidence.header.receiptsRoot
})
) revert L1_ANCHOR_RECEIPT_PROOF();
// Check the 1st receipt is for an InvalidateBlock tx with
// a BlockInvalidated event
LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(invalidateBlockReceipt);
if (receipt.status != 1) revert L1_ANCHOR_RECEIPT_STATUS();
if (receipt.logs.length != 1) revert L1_ANCHOR_RECEIPT_LOGS();
LibReceiptDecoder.Log memory log = receipt.logs[0];
if (
log.contractAddress !=
resolver.resolve(config.chainId, "taiko", false)
) revert L1_ANCHOR_RECEIPT_ADDR();
if (log.data.length != 0) revert L1_ANCHOR_RECEIPT_DATA();
if (
log.topics.length != 2 ||
log.topics[0] != INVALIDATE_BLOCK_LOG_TOPIC ||
log.topics[1] != target.txListHash
) revert L1_ANCHOR_RECEIPT_TOPICS();
}

function _validateAnchorTxSignature(
uint256 chainId,
LibTxDecoder.Tx memory _tx
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/libs/LibUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
import {LibMath} from "../../libs/LibMath.sol";
import {TaikoData} from "../TaikoData.sol";

/// @author dantaik <dan@taiko.xyz>
library LibUtils {
using LibMath for uint256;

Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/libs/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {TaikoData} from "../../L1/TaikoData.sol";

/**
* LibVerifying.
* @author dantaik <dan@taiko.xyz>
*/
library LibVerifying {
using SafeCastUpgradeable for uint256;
Expand Down
3 changes: 0 additions & 3 deletions packages/protocol/contracts/L2/TaikoL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ import {LibSharedConfig} from "../libs/LibSharedConfig.sol";
import {LibTxDecoder} from "../libs/LibTxDecoder.sol";
import {TaikoData} from "../L1/TaikoData.sol";

/**
* @author dantaik <dan@taiko.xyz>
*/
contract TaikoL2 is AddressResolver, ReentrancyGuard, IHeaderSync {
using LibTxDecoder for bytes;

Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/bridge/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {LibBridgeStatus} from "./libs/LibBridgeStatus.sol";
* Bridge contract which is deployed on both L1 and L2. Mostly a thin wrapper
* which calls the library implementations. See _IBridge_ for more details.
* @dev The code hash for the same address on L1 and L2 may be different.
* @author dantaik <dan@taiko.xyz>
*/
contract Bridge is EssentialContract, IBridge {
using LibBridgeData for Message;
Expand Down
3 changes: 0 additions & 3 deletions packages/protocol/contracts/bridge/BridgedERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ import {
import {EssentialContract} from "../common/EssentialContract.sol";
import {ERC20Upgradeable} from "../thirdparty/ERC20Upgradeable.sol";

/**
* @author dantaik <dan@taiko.xyz>
*/
contract BridgedERC20 is
EssentialContract,
IERC20Upgradeable,
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/bridge/EtherVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {LibAddress} from "../libs/LibAddress.sol";
* - Is initialized with 2^128 Ether.
* - Allows the contract owner to authorize addresses.
* - Allows authorized addresses to send/release Ether.
* @author dantaik <dan@taiko.xyz>
*/
contract EtherVault is EssentialContract {
using LibAddress for address;
Expand Down
Loading

0 comments on commit 9c3fb10

Please sign in to comment.