Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol): step 3 - enhance ZKP handling & change proofs order #288

Merged
merged 44 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ccd8859
Suspend the chain if we have two conflicting ZKP
dantaik Nov 18, 2022
9172b41
Update TaikoL1.sol
dantaik Nov 18, 2022
17cd13d
Update TaikoL1.sol
dantaik Nov 18, 2022
324f76f
Merge branch 'main' into security1
dantaik Nov 18, 2022
97e248d
change to use mask and allow more than one ZKPs per block.
dantaik Nov 19, 2022
ff16479
Update TaikoL1.sol
dantaik Nov 19, 2022
0a5d6e7
Update V1Proving.sol
dantaik Nov 19, 2022
d9fe820
format
dantaik Nov 19, 2022
4fbb0dd
Update TaikoL1.sol
dantaik Nov 19, 2022
59c5b65
more
dantaik Nov 19, 2022
ed1b313
format
dantaik Nov 19, 2022
92e84d1
improve
dantaik Nov 19, 2022
42de56f
Merge branch 'main' into security1
dantaik Nov 19, 2022
197eccc
Update V1Proving.sol
dantaik Nov 19, 2022
ec8f976
chore(ci): disable checking coverage against the base of the PR
davidtaikocha Nov 19, 2022
b45fa04
chore: update configs
davidtaikocha Nov 19, 2022
71ed2f8
chore: add flag_management
davidtaikocha Nov 19, 2022
0728bce
chore: try
davidtaikocha Nov 19, 2022
7ce3973
chore: try2
davidtaikocha Nov 19, 2022
ed2b8b0
Merge branch 'main' into security1
dantaik Nov 19, 2022
cecdbc7
fix tests
dantaik Nov 19, 2022
cd99670
fix tests
dantaik Nov 19, 2022
9d44a45
feat(protocol): enable whitelisting provers (disabled for now) (#287)
dantaik Nov 19, 2022
c65bec3
Merge branch 'main' into disable-codecov-project-patch
dantaik Nov 19, 2022
2426cf6
Merge branch 'disable-codecov-project-patch' into security1
dantaik Nov 19, 2022
96a1d7c
Update TaikoL1.sol
dantaik Nov 19, 2022
ac86375
reformat
dantaik Nov 19, 2022
de56ded
Update V1Proving.sol
dantaik Nov 19, 2022
9ca704b
Force a verification delay of 60 minutes
dantaik Nov 20, 2022
dfe3c86
Update V1Finalizing.sol
dantaik Nov 20, 2022
1e2af2f
Merge branch 'main' into disable-codecov-project-patch
dantaik Nov 20, 2022
211575a
Merge branch 'disable-codecov-project-patch' into security1
dantaik Nov 20, 2022
cddd1e6
Finalize -> Verify
dantaik Nov 20, 2022
2a2a8dd
Merge branch 'finalize_to_verify' into security1
dantaik Nov 20, 2022
f1ad2f5
Update V1Finalizing.sol
dantaik Nov 20, 2022
3fb5292
Merge branch 'main' into finalize_to_verify
dantaik Nov 21, 2022
8797388
Merge branch 'main' into finalize_to_verify
dantaik Nov 21, 2022
443123f
Merge branch 'finalize_to_verify' into security1
dantaik Nov 21, 2022
5c94382
Merge branch 'main' into security1
dantaik Nov 22, 2022
62576f5
Update TaikoL1.sol
dantaik Nov 22, 2022
e59859b
Update TestMessageSender.sol
dantaik Nov 22, 2022
4413541
Merge branch 'main' into security1
dantaik Nov 22, 2022
a1a56bb
Update TaikoL1.sol
dantaik Nov 22, 2022
07ae4f0
Update TaikoL1.sol
dantaik Nov 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/protocol/contracts/L1/LibData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ library LibData {
mapping(uint256 => mapping(bytes32 => ForkChoice)) forkChoices;
mapping(bytes32 => uint256) commits;
mapping(address => bool) provers; // Whitelisted provers
uint64 statusBits;
uint64 genesisHeight;
uint64 latestVerifiedHeight;
uint64 latestVerifiedId;
Expand Down
48 changes: 33 additions & 15 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import "../common/ConfigManager.sol";
import "../common/EssentialContract.sol";
import "../common/IHeaderSync.sol";
Expand All @@ -17,7 +19,7 @@ import "./v1/V1Events.sol";
import "./v1/V1Finalizing.sol";
import "./v1/V1Proposing.sol";
import "./v1/V1Proving.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
import "./v1/V1Utils.sol";

/**
* @author dantaik <dan@taiko.xyz>
Expand All @@ -28,7 +30,7 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
using SafeCastUpgradeable for uint256;

LibData.State public state;
uint256[44] private __gap;
uint256[43] private __gap;

function init(
address _addressManager,
Expand Down Expand Up @@ -73,7 +75,8 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
V1Proposing.proposeBlock(state, inputs);
V1Finalizing.verifyBlocks(
state,
LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX
LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX,
false
davidtaikocha marked this conversation as resolved.
Show resolved Hide resolved
);
}

Expand All @@ -99,7 +102,8 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
V1Proving.proveBlock(state, AddressResolver(this), blockIndex, inputs);
V1Finalizing.verifyBlocks(
state,
LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX
LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX,
false
);
}

Expand All @@ -117,7 +121,6 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
* on L2. Note that the `invalidBlock` transaction is supposed to
* be the only transaction in the L2 block.
*/

function proveBlockInvalid(
uint256 blockIndex,
bytes[] calldata inputs
Expand All @@ -130,12 +133,21 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
);
V1Finalizing.verifyBlocks(
state,
LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX
LibConstants.TAIKO_MAX_VERIFICATIONS_PER_TX,
false
);
}

/**
* Add or remove a prover from the whitelist.
* Finalize up to N blocks.
* @param maxBlocks Max number of blocks to finalize.
*/
function verifyBlocks(uint256 maxBlocks) external nonReentrant {
require(maxBlocks > 0, "L1:maxBlocks");
V1Finalizing.verifyBlocks(state, maxBlocks, true);
}

/* Add or remove a prover from the whitelist.
*
* @param prover The prover to be added or removed.
* @param whitelisted True to add; remove otherwise.
Expand All @@ -148,7 +160,15 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
}

/**
* Return whether a prover is whitelisted.
* Halt or resume the chain.
* @param toHalt True to halt, false to resume.
*/
function halt(bool toHalt) public onlyOwner {
V1Utils.halt(state, toHalt);
}

/**
* Check whether a prover is whitelisted.
*
* @param prover The prover.
* @return True if the prover is whitelisted, false otherwise.
Expand All @@ -157,14 +177,12 @@ contract TaikoL1 is EssentialContract, IHeaderSync, V1Events {
return V1Proving.isProverWhitelisted(state, prover);
}


/**
* Verify up to N blocks.
* @param maxBlocks Max number of blocks to verify.
/**
* Check if the L1 is halted.
* @return True if halted, false otherwise.
*/
function verifyBlocks(uint256 maxBlocks) external nonReentrant {
require(maxBlocks > 0, "L1:maxBlocks");
V1Finalizing.verifyBlocks(state, maxBlocks);
function isHalted() public view returns (bool) {
return V1Utils.isHalted(state);
}

function isCommitValid(bytes32 hash) public view returns (bool) {
Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/contracts/L1/v1/V1Events.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ abstract contract V1Events {
);

event ProverWhitelisted(address indexed prover, bool whitelisted);

event Halted(bool halted);
}
27 changes: 23 additions & 4 deletions packages/protocol/contracts/L1/v1/V1Finalizing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import "../LibData.sol";
import "./V1Utils.sol";

/// @author dantaik <dan@taiko.xyz>
library V1Finalizing {
Expand All @@ -31,7 +29,19 @@ library V1Finalizing {
emit HeaderSynced(block.number, 0, _genesisBlockHash);
}

function verifyBlocks(LibData.State storage s, uint256 maxBlocks) public {
function verifyBlocks(
LibData.State storage s,
uint256 maxBlocks,
bool checkHalt
) public {
bool halted = V1Utils.isHalted(s);
if (checkHalt) {
require(!halted, "L1:halted");
} else if (halted) {
// skip finalizing blocks
return;
}

uint64 latestL2Height = s.latestVerifiedHeight;
bytes32 latestL2Hash = s.l2Hashes[latestL2Height];
uint64 processed = 0;
Expand All @@ -43,6 +53,15 @@ library V1Finalizing {
) {
LibData.ForkChoice storage fc = s.forkChoices[i][latestL2Hash];

// TODO(daniel): use the average proof-time.
if (
block.timestamp <=
fc.provenAt + LibConstants.K_VERIFICATION_DELAY
) {
// This block is proven but still needs to wait for verificaiton.
break;
}

if (fc.blockHash == LibConstants.TAIKO_BLOCK_DEADEND_HASH) {
emit BlockVerified(i, 0);
} else if (fc.blockHash != 0) {
Expand Down
11 changes: 8 additions & 3 deletions packages/protocol/contracts/L1/v1/V1Proposing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import "../../common/ConfigManager.sol";
import "../../libs/LibConstants.sol";
import "../../libs/LibTxDecoder.sol";
import "../LibData.sol";
import "./V1Utils.sol";

/// @author dantaik <dan@taiko.xyz>
library V1Proposing {
Expand All @@ -25,6 +23,11 @@ library V1Proposing {
event BlockProposed(uint256 indexed id, LibData.BlockMetadata meta);

function commitBlock(LibData.State storage s, bytes32 commitHash) public {
// It's OK to allow committing block when the system is halt.
// By not checking the halt status, this method will be cheaper.
//
// require(!V1Utils.isHalted(s), "L1:halt");

require(commitHash != 0, "L1:hash");
require(s.commits[commitHash] == 0, "L1:committed");
s.commits[commitHash] = block.number;
Expand All @@ -39,6 +42,8 @@ library V1Proposing {
LibData.State storage s,
bytes[] calldata inputs
) public {
require(!V1Utils.isHalted(s), "L1:halt");

require(inputs.length == 2, "L1:inputs:size");
LibData.BlockMetadata memory meta = abi.decode(
inputs[0],
Expand Down
58 changes: 38 additions & 20 deletions packages/protocol/contracts/L1/v1/V1Proving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import "../../common/AddressResolver.sol";
import "../../common/ConfigManager.sol";
import "../../libs/LibAnchorSignature.sol";
Expand All @@ -22,7 +20,7 @@ import "../../libs/LibZKP.sol";
import "../../thirdparty/LibBytesUtils.sol";
import "../../thirdparty/LibMerkleTrie.sol";
import "../../thirdparty/LibRLPWriter.sol";
import "../LibData.sol";
import "./V1Utils.sol";

/// @author dantaik <dan@taiko.xyz>
/// @author david <david@taiko.xyz>
Expand All @@ -34,7 +32,7 @@ library V1Proving {
LibData.BlockMetadata meta;
BlockHeader header;
address prover;
bytes[] proofs;
bytes[] proofs; // The first K_ZKPROOFS_PER_BLOCK are ZKPs
Brechtpd marked this conversation as resolved.
Show resolved Hide resolved
}

event BlockProven(
Expand All @@ -61,6 +59,8 @@ library V1Proving {
uint256 blockIndex,
bytes[] calldata inputs
) public onlyWhitelistedProver(s) {
require(!V1Utils.isHalted(s), "L1:halt");

// Check and decode inputs
require(inputs.length == 3, "L1:inputs:size");
Evidence memory evidence = abi.decode(inputs[0], (Evidence));
Expand All @@ -69,7 +69,10 @@ library V1Proving {

// Check evidence
require(evidence.meta.id == blockIndex, "L1:id");
require(evidence.proofs.length == 3, "L1:proof:size");
require(
evidence.proofs.length == 2 + LibConstants.K_ZKPROOFS_PER_BLOCK,
"L1:proof:size"
);

// Check anchor tx is valid
LibTxDecoder.Tx memory _tx = LibTxDecoder.decodeTx(anchorTx);
Expand Down Expand Up @@ -105,7 +108,7 @@ library V1Proving {
LibMerkleTrie.verifyInclusionProof(
LibRLPWriter.writeUint(0),
anchorTx,
evidence.proofs[1],
evidence.proofs[LibConstants.K_ZKPROOFS_PER_BLOCK],
evidence.header.transactionsRoot
),
"L1:tx:proof"
Expand All @@ -120,7 +123,7 @@ library V1Proving {
LibMerkleTrie.verifyInclusionProof(
LibRLPWriter.writeUint(0),
anchorReceipt,
evidence.proofs[2],
evidence.proofs[LibConstants.K_ZKPROOFS_PER_BLOCK + 1],
evidence.header.receiptsRoot
),
"L1:receipt:proof"
Expand All @@ -136,6 +139,8 @@ library V1Proving {
uint256 blockIndex,
bytes[] calldata inputs
) public onlyWhitelistedProver(s) {
require(!V1Utils.isHalted(s), "L1:halt");

// Check and decode inputs
require(inputs.length == 3, "L1:inputs:size");
Evidence memory evidence = abi.decode(inputs[0], (Evidence));
Expand All @@ -147,7 +152,10 @@ library V1Proving {

// Check evidence
require(evidence.meta.id == blockIndex, "L1:id");
require(evidence.proofs.length == 2, "L1:proof:size");
require(
evidence.proofs.length == 1 + LibConstants.K_ZKPROOFS_PER_BLOCK,
"L1:proof:size"
);

// Check the 1st receipt is for an InvalidateBlock tx with
// a BlockInvalidated event
Expand Down Expand Up @@ -175,7 +183,7 @@ library V1Proving {
LibMerkleTrie.verifyInclusionProof(
LibRLPWriter.writeUint(0),
invalidateBlockReceipt,
evidence.proofs[1],
evidence.proofs[LibConstants.K_ZKPROOFS_PER_BLOCK],
evidence.header.receiptsRoot
),
"L1:receipt:proof"
Expand Down Expand Up @@ -229,15 +237,17 @@ library V1Proving {

bytes32 blockHash = evidence.header.hashBlockHeader();

LibZKP.verify(
ConfigManager(resolver.resolve("config_manager")).getValue(
"zk_vkey"
),
evidence.proofs[0],
blockHash,
evidence.prover,
evidence.meta.txListHash
);
for (uint i = 0; i < LibConstants.K_ZKPROOFS_PER_BLOCK; i++) {
LibZKP.verify(
ConfigManager(resolver.resolve("config_manager")).getValue(
string(abi.encodePacked("zk_vkey_", i))
),
evidence.proofs[i],
blockHash,
evidence.prover,
evidence.meta.txListHash
);
}

_markBlockProven(
s,
Expand All @@ -263,9 +273,17 @@ library V1Proving {
fc.provenAt = uint64(block.timestamp);
} else {
require(
fc.blockHash == blockHash && fc.proposedAt == target.timestamp,
"L1:proof:conflict"
fc.proposedAt == target.timestamp,
"L1:proposedAt:conflict"
);

if (fc.blockHash != blockHash) {
// We have a problem here: two proofs are both valid but claims
// the new block has different hashes.
V1Utils.halt(s, true);
return;
}
Brechtpd marked this conversation as resolved.
Show resolved Hide resolved

require(
fc.provers.length <
LibConstants.TAIKO_MAX_PROOFS_PER_FORK_CHOICE,
Expand Down
42 changes: 42 additions & 0 deletions packages/protocol/contracts/L1/v1/V1Utils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
//
// ╭━━━━╮╱╱╭╮╱╱╱╱╱╭╮╱╱╱╱╱╭╮
// ┃╭╮╭╮┃╱╱┃┃╱╱╱╱╱┃┃╱╱╱╱╱┃┃
// ╰╯┃┃┣┻━┳┫┃╭┳━━╮┃┃╱╱╭━━┫╰━┳━━╮
// ╱╱┃┃┃╭╮┣┫╰╯┫╭╮┃┃┃╱╭┫╭╮┃╭╮┃━━┫
// ╱╱┃┃┃╭╮┃┃╭╮┫╰╯┃┃╰━╯┃╭╮┃╰╯┣━━┃
// ╱╱╰╯╰╯╰┻┻╯╰┻━━╯╰━━━┻╯╰┻━━┻━━╯
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import "../../libs/LibMath.sol";
import "../LibData.sol";

/// @author dantaik <dan@taiko.xyz>
library V1Utils {
uint64 public constant MASK_HALT = 1 << 0;
dantaik marked this conversation as resolved.
Show resolved Hide resolved

event Halted(bool halted);

function halt(LibData.State storage s, bool toHalt) public {
require(isHalted(s) != toHalt, "L1:precondition");
setBit(s, MASK_HALT, toHalt);
emit Halted(toHalt);
}

function isHalted(LibData.State storage s) public view returns (bool) {
return isBitOne(s, MASK_HALT);
}

function setBit(LibData.State storage s, uint64 mask, bool one) private {
s.statusBits = one ? s.statusBits | mask : s.statusBits & ~mask;
}

function isBitOne(
LibData.State storage s,
uint64 mask
) private view returns (bool) {
return s.statusBits & mask != 0;
}
}
Loading