Skip to content

Commit

Permalink
refactor(protocol): extract IProofVerifier interface (#6800)
Browse files Browse the repository at this point in the history
  • Loading branch information
dong77 authored Jan 3, 2023
1 parent 0cbe6db commit 470afdf
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 64 deletions.
64 changes: 64 additions & 0 deletions packages/protocol/contracts/L1/ProofVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
//
// ╭━━━━╮╱╱╭╮╱╱╱╱╱╭╮╱╱╱╱╱╭╮
// ┃╭╮╭╮┃╱╱┃┃╱╱╱╱╱┃┃╱╱╱╱╱┃┃
// ╰╯┃┃┣┻━┳┫┃╭┳━━╮┃┃╱╱╭━━┫╰━┳━━╮
// ╱╱┃┃┃╭╮┣┫╰╯┫╭╮┃┃┃╱╭┫╭╮┃╭╮┃━━┫
// ╱╱┃┃┃╭╮┃┃╭╮┫╰╯┃┃╰━╯┃╭╮┃╰╯┣━━┃
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import "../thirdparty/LibMerkleTrie.sol";
import "../libs/LibZKP.sol";

/// @author dantaik <[email protected]>
interface IProofVerifier {
function verifyZKP(
bytes memory verificationKey,
bytes calldata zkproof,
bytes32 blockHash,
address prover,
bytes32 txListHash
) external pure returns (bool verified);

function verifyMKP(
bytes memory key,
bytes memory value,
bytes memory proof,
bytes32 root
) external pure returns (bool verified);
}

contract ProofVerifier is IProofVerifier {
function verifyZKP(
bytes memory verificationKey,
bytes calldata zkproof,
bytes32 blockHash,
address prover,
bytes32 txListHash
) external pure returns (bool) {
return
LibZKP.verify({
verificationKey: verificationKey,
zkproof: zkproof,
blockHash: blockHash,
prover: prover,
txListHash: txListHash
});
}

function verifyMKP(
bytes memory key,
bytes memory value,
bytes memory proof,
bytes32 root
) external pure returns (bool) {
return
LibMerkleTrie.verifyInclusionProof({
_key: key,
_value: value,
_proof: proof,
_root: root
});
}
}
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ library TaikoData {
uint64 boostrapDiscountHalvingPeriod;
uint64 initialUncleDelay;
bool enableTokenomics;
bool skipProofValidation;
}

struct BlockMetadata {
Expand Down
107 changes: 58 additions & 49 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import {IProofVerifier} from "../ProofVerifier.sol";
import "../../common/AddressResolver.sol";
import "../../common/ConfigManager.sol";
import "../../libs/LibAnchorSignature.sol";
import "../../libs/LibBlockHeader.sol";
import "../../libs/LibReceiptDecoder.sol";
import "../../libs/LibTxDecoder.sol";
import "../../libs/LibTxUtils.sol";
import "../../libs/LibZKP.sol";
import "../../thirdparty/LibBytesUtils.sol";
import "../../thirdparty/LibMerkleTrie.sol";
import "../../thirdparty/LibRLPWriter.sol";
import "./LibUtils.sol";

Expand Down Expand Up @@ -107,40 +106,43 @@ library LibProving {
);
}

if (!config.skipProofValidation) {
// Check anchor tx is the 1st tx in the block
require(
LibMerkleTrie.verifyInclusionProof({
_key: LibRLPWriter.writeUint(0),
_value: anchorTx,
_proof: evidence.proofs[zkProofsPerBlock],
_root: evidence.header.transactionsRoot
}),
"L1:tx:proof"
);
IProofVerifier proofVerifier = IProofVerifier(
resolver.resolve("proof_verifier")
);

// Check anchor tx does not throw
// Check anchor tx is the 1st tx in the block
require(
proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: anchorTx,
proof: evidence.proofs[zkProofsPerBlock],
root: evidence.header.transactionsRoot
}),
"L1:tx:proof"
);

LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(anchorReceipt);
// Check anchor tx does not throw

require(receipt.status == 1, "L1:receipt:status");
require(
LibMerkleTrie.verifyInclusionProof({
_key: LibRLPWriter.writeUint(0),
_value: anchorReceipt,
_proof: evidence.proofs[zkProofsPerBlock + 1],
_root: evidence.header.receiptsRoot
}),
"L1:receipt:proof"
);
}
LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(anchorReceipt);

require(receipt.status == 1, "L1:receipt:status");
require(
proofVerifier.verifyMKP({
key: LibRLPWriter.writeUint(0),
value: anchorReceipt,
proof: evidence.proofs[zkProofsPerBlock + 1],
root: evidence.header.receiptsRoot
}),
"L1:receipt:proof"
);

// ZK-prove block and mark block proven to be valid.
_proveBlock({
state: state,
config: config,
resolver: resolver,
proofVerifier: proofVerifier,
evidence: evidence,
target: evidence.meta,
blockHashOverride: 0
Expand Down Expand Up @@ -172,14 +174,29 @@ library LibProving {
"L1:proof:size"
);

if (!config.skipProofValidation) {
// Check the 1st receipt is for an InvalidateBlock tx with
// a BlockInvalidated event
LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(invalidateBlockReceipt);
require(receipt.status == 1, "L1:receipt:status");
require(receipt.logs.length == 1, "L1:receipt:logsize");
IProofVerifier proofVerifier = IProofVerifier(
resolver.resolve("proof_verifier")
);

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

// Check the 1st receipt is for an InvalidateBlock tx with
// a BlockInvalidated event
LibReceiptDecoder.Receipt memory receipt = LibReceiptDecoder
.decodeReceipt(invalidateBlockReceipt);
require(receipt.status == 1, "L1:receipt:status");
require(receipt.logs.length == 1, "L1:receipt:logsize");

{
LibReceiptDecoder.Log memory log = receipt.logs[0];
require(
log.contractAddress ==
Expand All @@ -193,24 +210,14 @@ library LibProving {
log.topics[1] == target.txListHash,
"L1:receipt:topics"
);

// Check the event is the first one in the throw-away block
require(
LibMerkleTrie.verifyInclusionProof({
_key: LibRLPWriter.writeUint(0),
_value: invalidateBlockReceipt,
_proof: evidence.proofs[config.zkProofsPerBlock],
_root: evidence.header.receiptsRoot
}),
"L1:receipt:proof"
);
}

// ZK-prove block and mark block proven as invalid.
_proveBlock({
state: state,
config: config,
resolver: resolver,
proofVerifier: proofVerifier,
evidence: evidence,
target: target,
blockHashOverride: LibUtils.BLOCK_DEADEND_HASH
Expand All @@ -221,6 +228,7 @@ library LibProving {
TaikoData.State storage state,
TaikoData.Config memory config,
AddressResolver resolver,
IProofVerifier proofVerifier,
Evidence memory evidence,
TaikoData.BlockMetadata memory target,
bytes32 blockHashOverride
Expand All @@ -238,17 +246,18 @@ library LibProving {
bytes32 blockHash = evidence.header.hashBlockHeader();

for (uint256 i = 0; i < config.zkProofsPerBlock; ++i) {
if (!config.skipProofValidation) {
LibZKP.verify({
require(
proofVerifier.verifyZKP({
verificationKey: ConfigManager(
resolver.resolve("config_manager")
).getValue(string(abi.encodePacked("zk_vkey_", i))),
zkproof: evidence.proofs[i],
blockHash: blockHash,
prover: evidence.prover,
txListHash: evidence.meta.txListHash
});
}
}),
"L1:zkp"
);
}

_markBlockProven({
Expand Down
3 changes: 1 addition & 2 deletions packages/protocol/contracts/libs/LibSharedConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ library LibSharedConfig {
proofTimeCap: 60 minutes,
boostrapDiscountHalvingPeriod: 180 days,
initialUncleDelay: 60 minutes,
enableTokenomics: false,
skipProofValidation: false
enableTokenomics: false
});
}
}
2 changes: 1 addition & 1 deletion packages/protocol/contracts/libs/LibZKP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ library LibZKP {
bytes32 blockHash,
address prover,
bytes32 txListHash
) public pure {
) internal pure returns (bool verified) {
// TODO
}
}
23 changes: 21 additions & 2 deletions packages/protocol/contracts/test/L1/TestTaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import {IProofVerifier} from "../../L1/ProofVerifier.sol";
import "../../L1/TaikoL1.sol";

contract TestTaikoL1NoTokenomicsNoProofValidation is TaikoL1 {
contract TestTaikoL1 is TaikoL1, IProofVerifier {
function getConfig()
public
pure
Expand Down Expand Up @@ -49,6 +50,24 @@ contract TestTaikoL1NoTokenomicsNoProofValidation is TaikoL1 {
config.boostrapDiscountHalvingPeriod = 180 days;
config.initialUncleDelay = 1 minutes;
config.enableTokenomics = false;
config.skipProofValidation = true;
}

function verifyZKP(
bytes memory /*verificationKey*/,
bytes calldata /*zkproof*/,
bytes32 /*blockHash*/,
address /*prover*/,
bytes32 /*txListHash*/
) public pure override returns (bool) {
return true;
}

function verifyMKP(
bytes memory /*key*/,
bytes memory /*value*/,
bytes memory /*proof*/,
bytes32 /*root*/
) public pure override returns (bool) {
return true;
}
}
9 changes: 7 additions & 2 deletions packages/protocol/tasks/deploy_L1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ export async function deployContracts(hre: any) {
// AddressManager
const AddressManager = await utils.deployContract(hre, "AddressManager");
await utils.waitTx(hre, await AddressManager.init());

const ProofVerifier = await utils.deployContract(hre, "ProofVerifier");
await utils.waitTx(
hre,
await AddressManager.setAddress(`${chainId}.proof_verifier`, ProofVerifier.address)
);

await utils.waitTx(
hre,
await AddressManager.setAddress(`${chainId}.dao_vault`, daoVault)
Expand Down Expand Up @@ -195,7 +202,6 @@ export async function deployContracts(hre: any) {
}

async function deployBaseLibs(hre: any) {
const libZKP = await utils.deployContract(hre, "LibZKP");
const libReceiptDecoder = await utils.deployContract(
hre,
"LibReceiptDecoder"
Expand All @@ -206,7 +212,6 @@ async function deployBaseLibs(hre: any) {
const libProposing = await utils.deployContract(hre, "LibProposing", {});

const libProving = await utils.deployContract(hre, "LibProving", {
LibZKP: libZKP.address,
LibReceiptDecoder: libReceiptDecoder.address,
LibTxDecoder: libTxDecoder.address,
});
Expand Down
9 changes: 2 additions & 7 deletions packages/protocol/test/L1/TaikoL1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ describe("TaikoL1", function () {
await ethers.getContractFactory("LibTxDecoder")
).deploy();

const libZKP = await (
await ethers.getContractFactory("LibZKP")
).deploy();

const libProposing = await (
await ethers.getContractFactory("LibProposing")
).deploy();
Expand All @@ -33,8 +29,7 @@ describe("TaikoL1", function () {
await ethers.getContractFactory("LibProving", {
libraries: {
LibReceiptDecoder: libReceiptDecoder.address,
LibTxDecoder: libTxDecoder.address,
LibZKP: libZKP.address,
LibTxDecoder: libTxDecoder.address
},
})
).deploy();
Expand All @@ -47,7 +42,7 @@ describe("TaikoL1", function () {
const feeBase = BigNumber.from(10).pow(18);
taikoL1 = await (
await ethers.getContractFactory(
"TestTaikoL1NoTokenomicsNoProofValidation",
"TestTaikoL1",
{
libraries: {
LibVerifying: libVerifying.address,
Expand Down

0 comments on commit 470afdf

Please sign in to comment.