Skip to content

Commit

Permalink
Composite proof (#41)
Browse files Browse the repository at this point in the history
* feat: two of three proving

* feat: Add CombinedProducer

* feat: Add TwoOfThree tier

* linter fix

* fix: define verifier flags for composite proof

* getProvider for the TierProviderV2

* tire providers deployment for: devnet, testnet, composite

* fix: add tier to provide base

* guardian removed from the prover

* fixed hanging CombinedProducer
close(errorsChan) and added proofStates

* lint

* Allow empty blocks flag (#45)

* feat: disable external pausing

* feat: add allowEmptyBlocks flag in proposer

* Fixed ProofStates map in combined producer

* test getTiers

* test fix

* guardian = false for  tx builder

* feat: change l2-l1 sync interval to 1 block (#46)

* feat: change l2-l1 sync interval to 1 block

* fix: naming of composite tier

* feat: remove access controls from verifiers

* always init with empty block

---------

Co-authored-by: Maciej Skrzypkowski <mskr@gmx.com>

---------

Co-authored-by: AnshuJalan <anshujalan206@gmail.com>
Co-authored-by: Franco Barpp Gomes <franco@nethermind.io>
Co-authored-by: nmjustinchan <justin.chan@nethermind.io>
Co-authored-by: Maciej Skrzypkowski <mskr@gmx.com>
Co-authored-by: Justin Chan <147025745+nmjustinchan@users.noreply.github.com>
  • Loading branch information
6 people authored Dec 24, 2024
1 parent d6706a2 commit e5000b0
Show file tree
Hide file tree
Showing 32 changed files with 597 additions and 378 deletions.
3 changes: 2 additions & 1 deletion packages/protocol/contracts/layer1/based/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents {

/// @inheritdoc ITaikoL1
function pauseProving(bool _pause) external {
_disable();
_authorizePause(msg.sender, _pause);
LibProving.pauseProving(state, _pause);
}
Expand Down Expand Up @@ -296,7 +297,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents {
maxBlocksToVerify: 16,
blockMaxGasLimit: 240_000_000,
livenessBond: 0.07 ether,
stateRootSyncInternal: 16,
stateRootSyncInternal: 1,
maxAnchorHeightOffset: 64,
baseFeeConfig: LibSharedData.BaseFeeConfig({
adjustmentQuotient: 8,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ contract DevnetTierProvider is TierProviderBase, ITierRouter {

/// @inheritdoc ITierProvider
function getTierIds() public pure override returns (uint16[] memory tiers_) {
tiers_ = new uint16[](3);
tiers_ = new uint16[](4);
tiers_[0] = LibTiers.TIER_OPTIMISTIC;
tiers_[1] = LibTiers.TIER_GUARDIAN_MINORITY;
tiers_[2] = LibTiers.TIER_GUARDIAN;
tiers_[3] = LibTiers.TIER_TWO_OF_THREE;
}

/// @inheritdoc ITierProvider
Expand Down
3 changes: 3 additions & 0 deletions packages/protocol/contracts/layer1/tiers/LibTiers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ library LibTiers {

/// @notice Guardian tier ID with majority approval.
uint16 public constant TIER_GUARDIAN = 1000;

/// @notice Requires 2/3 proofs from SGX/RISC/SP1
uint16 public constant TIER_TWO_OF_THREE = 1100;
}
5 changes: 5 additions & 0 deletions packages/protocol/contracts/layer1/tiers/TierProviderBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ abstract contract TierProviderBase is ITierProvider {
return _buildTier(LibStrings.B_TIER_GUARDIAN, 0, 1440, 2880);
}

if (_tierId == LibTiers.TIER_TWO_OF_THREE) {
// No validity bond or cooldown.
return _buildTier(LibStrings.B_TIER_TWO_OF_THREE, 0, 0, 180);
}

revert TIER_NOT_FOUND();
}

Expand Down
16 changes: 10 additions & 6 deletions packages/protocol/contracts/layer1/tiers/TierProviderV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@
pragma solidity ^0.8.24;

import "./TierProviderBase.sol";
import "./ITierRouter.sol";

/// @title TierProviderV2
/// @custom:security-contact security@taiko.xyz
contract TierProviderV2 is TierProviderBase {
contract TierProviderV2 is TierProviderBase, ITierRouter {
/// @inheritdoc ITierRouter
function getProvider(uint256) external view returns (address) {
return address(this);
}

/// @inheritdoc ITierProvider
function getTierIds() public pure override returns (uint16[] memory tiers_) {
tiers_ = new uint16[](3);
tiers_[0] = LibTiers.TIER_SGX;
tiers_[1] = LibTiers.TIER_GUARDIAN_MINORITY;
tiers_[2] = LibTiers.TIER_GUARDIAN;
tiers_ = new uint16[](1);
tiers_[0] = LibTiers.TIER_TWO_OF_THREE;
}

/// @inheritdoc ITierProvider
function getMinTier(address, uint256) public pure override returns (uint16) {
return LibTiers.TIER_SGX;
return LibTiers.TIER_TWO_OF_THREE;
}
}
3 changes: 2 additions & 1 deletion packages/protocol/contracts/layer1/verifiers/SgxVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,9 @@ contract SgxVerifier is EssentialContract, IVerifier {
TaikoData.TierProof calldata _proof
)
external
onlyFromNamedEither(LibStrings.B_TAIKO, LibStrings.B_TIER_TEE_ANY)
{
// ^ Access controls removed for testnet.

// Do not run proof verification to contest an existing proof
if (_ctx.isContesting) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ abstract contract ComposeVerifier is EssentialContract, IVerifier {
TaikoData.TierProof calldata _proof
)
external
onlyAuthorizedCaller
nonReentrant
{
(address[] memory verifiers, uint256 numSubProofs_) = getSubVerifiersAndThreshold();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "src/shared/common/LibStrings.sol";
import "./ComposeVerifier.sol";

/// @title TwoOfThreeVerifier
/// @custom:security-contact security@taiko.xyz
contract TwoOfThreeVerifier is ComposeVerifier {
uint256[50] private __gap;

/// @inheritdoc ComposeVerifier
function getSubVerifiersAndThreshold()
public
view
override
returns (address[] memory verifiers_, uint256 numSubProofs_)
{
verifiers_ = new address[](3);
verifiers_[0] = resolve(LibStrings.B_TIER_ZKVM_RISC0, true);
verifiers_[1] = resolve(LibStrings.B_TIER_ZKVM_SP1, true);
verifiers_[2] = resolve(LibStrings.B_TIER_SGX, true);
numSubProofs_ = 2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
error REENTRANT_CALL();
error ZERO_ADDRESS();
error ZERO_VALUE();
error FUNCTION_DISABLED();

/// @dev Modifier that ensures the caller is the owner or resolved address of a given name.
/// @param _name The name to check against.
Expand Down Expand Up @@ -78,6 +79,7 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,

/// @notice Pauses the contract.
function pause() public virtual {
_disable();
_pause();
// We call the authorize function here to avoid:
// Warning (5740): Unreachable code.
Expand Down Expand Up @@ -137,6 +139,10 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
emit Unpaused(msg.sender);
}

function _disable() internal pure {
revert FUNCTION_DISABLED();
}

function _authorizeUpgrade(address) internal virtual override onlyOwner { }

function _authorizePause(address, bool) internal virtual onlyOwner { }
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/contracts/shared/common/LibStrings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ library LibStrings {
bytes32 internal constant B_TIER_ZKVM_SP1 = bytes32("tier_zkvm_sp1");
bytes32 internal constant B_TIER_ZKVM_ANY = bytes32("tier_zkvm_any");
bytes32 internal constant B_TIER_ZKVM_AND_TEE = bytes32("tier_zkvm_and_tee");
bytes32 internal constant B_TIER_TWO_OF_THREE = bytes32("tier_two_of_three");
bytes32 internal constant B_RISCZERO_GROTH16_VERIFIER = bytes32("risc0_groth16_verifier");
bytes32 internal constant B_WITHDRAWER = bytes32("withdrawer");
bytes32 internal constant H_RETURN_LIVENESS_BOND = keccak256("RETURN_LIVENESS_BOND");
Expand Down
13 changes: 12 additions & 1 deletion packages/protocol/script/layer1/DeployProtocolOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import "src/layer1/provers/GuardianProver.sol";
import "src/layer1/tiers/TierProviderV2.sol";
import "src/layer1/verifiers/Risc0Verifier.sol";
import "src/layer1/verifiers/SP1Verifier.sol";
import "src/layer1/verifiers/compose/TwoOfThreeVerifier.sol";
import "src/layer1/verifiers/compose/ComposeVerifier.sol";
import "test/layer1/based/TestTierProvider.sol";
import "test/shared/token/FreeMintERC20.sol";
import "test/shared/token/MayFailFreeMintERC20.sol";
Expand Down Expand Up @@ -373,6 +375,14 @@ contract DeployProtocolOnL1 is DeployCapability {
console2.log("AutomataDcapVaAttestation", automataProxy);

deployZKVerifiers(owner, rollupAddressManager);

// Deploy composite verifier
deployProxy({
name: "tier_two_of_three",
impl: address(new TwoOfThreeVerifier()),
data: abi.encodeCall(ComposeVerifier.init, (owner, rollupAddressManager)),
registerTo: rollupAddressManager
});
}

// deploy both sp1 & risc0 verifiers.
Expand Down Expand Up @@ -402,12 +412,13 @@ contract DeployProtocolOnL1 is DeployCapability {
});
}


function deployTierProvider(string memory tierProviderName) private returns (address) {
if (keccak256(abi.encode(tierProviderName)) == keccak256(abi.encode("devnet"))) {
return address(new DevnetTierProvider());
} else if (keccak256(abi.encode(tierProviderName)) == keccak256(abi.encode("testnet"))) {
return address(new TestTierProvider());
} else if (keccak256(abi.encode(tierProviderName)) == keccak256(abi.encode("mainnet"))) {
} else if (keccak256(abi.encode(tierProviderName)) == keccak256(abi.encode("composite"))) {
return address(new TierProviderV2());
} else {
revert("invalid tier provider");
Expand Down
37 changes: 0 additions & 37 deletions packages/protocol/test/layer1/based/TaikoL1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -182,43 +182,6 @@ contract TaikoL1Tests is TaikoL1TestBase {
}
}

function test_pauseProving() external {
L1.pauseProving(true);

TaikoData.BlockMetadata memory meta;

giveEthAndDepositBond(Alice, 1000 ether, 1000 ether);
giveEthAndDepositBond(Bob, 1000 ether, 1000 ether);

// Proposing is still possible
(meta,) = proposeBlock(Alice, 1024);
// Proving is not, so supply the revert reason to proveBlock
proveBlock(
Bob,
meta,
GENESIS_BLOCK_HASH,
bytes32("01"),
bytes32("02"),
meta.minTier,
LibProving.L1_PROVING_PAUSED.selector
);
}

function test_unpause() external {
giveEthAndDepositBond(Alice, 1000 ether, 1000 ether);

L1.pause();

// Proposing is also not possible
proposeButRevert(Alice, 1024, EssentialContract.INVALID_PAUSE_STATUS.selector);

// unpause
L1.unpause();

// Proposing is possible again
proposeBlock(Alice, 1024);
}

function test_getTierIds() external {
uint16[] memory tiers = cp.getTierIds();
assertEq(tiers[0], LibTiers.TIER_OPTIMISTIC);
Expand Down
98 changes: 0 additions & 98 deletions packages/protocol/test/layer1/based/TaikoL1TestGroup8.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,6 @@ pragma solidity ^0.8.24;
import "./TaikoL1TestGroupBase.sol";

contract TaikoL1TestGroup8 is TaikoL1TestGroupBase {
// Test summary:
// 1. Alice proposes a block,
// 2. TaikoL1 is paused.
// 3. Alice attempts to prove the block within the proving window.
// 4. Alice tries to propose another block.
// 5. TaikoL1 is unpaused.
// 6. Alice attempts again to prove the first block within the proving window.
// 7. Alice tries to propose another block.
function test_taikoL1_group_8_case_1() external {
vm.warp(1_000_000);
giveEthAndDepositBond(Alice, 1000 ether, 1000 ether);

console2.log("====== Alice propose a block");

TaikoData.BlockMetadata memory meta = proposeBlock(Alice, "");

console2.log("====== Pause TaikoL1");
mineAndWrap(10 seconds);
vm.prank(L1.owner());
L1.pause();

console2.log("====== Alice proves the block first after L1 paused");

bytes32 parentHash1 = GENESIS_BLOCK_HASH;
bytes32 blockHash = bytes32(uint256(10));
bytes32 stateRoot = bytes32(uint256(11));
proveBlock(
Alice,
meta,
parentHash1,
blockHash,
stateRoot,
meta.minTier,
EssentialContract.INVALID_PAUSE_STATUS.selector
);

console2.log("====== Alice tries to propose another block after L1 paused");
proposeBlock(Alice, EssentialContract.INVALID_PAUSE_STATUS.selector);

console2.log("====== Unpause TaikoL1");
mineAndWrap(10 seconds);
vm.prank(L1.owner());
L1.unpause();

console2.log("====== Alice proves the block first after L1 unpaused");
proveBlock(Alice, meta, parentHash1, blockHash, stateRoot, meta.minTier, "");
console2.log("====== Alice tries to propose another block after L1 unpaused");
proposeBlock(Alice, "");
}

// Test summary:
// 1. Alice proposes a block,
// 2. TaikoL1 proving is paused.
// 3. Alice attempts to prove the block within the proving window.
// 4. Alice tries to propose another block.
// 5. TaikoL1 proving is unpaused.
// 6. Alice attempts again to prove the first block within the proving window.
// 7. Alice tries to propose another block.
function test_taikoL1_group_8_case_2() external {
vm.warp(1_000_000);
giveEthAndDepositBond(Alice, 1000 ether, 1000 ether);

console2.log("====== Alice propose a block");

TaikoData.BlockMetadata memory meta = proposeBlock(Alice, "");

console2.log("====== Pause TaikoL1 proving");
mineAndWrap(10 seconds);
vm.prank(L1.owner());
L1.pauseProving(true);

console2.log("====== Alice proves the block first after L1 proving paused");

bytes32 parentHash1 = GENESIS_BLOCK_HASH;
bytes32 blockHash = bytes32(uint256(10));
bytes32 stateRoot = bytes32(uint256(11));
proveBlock(
Alice,
meta,
parentHash1,
blockHash,
stateRoot,
meta.minTier,
LibProving.L1_PROVING_PAUSED.selector
);

console2.log("====== Alice tries to propose another block after L1 proving paused");
proposeBlock(Alice, "");

console2.log("====== Unpause TaikoL1 proving");
mineAndWrap(10 seconds);
vm.prank(L1.owner());
L1.pauseProving(false);

console2.log("====== Alice proves the block first after L1 proving unpaused");
proveBlock(Alice, meta, parentHash1, blockHash, stateRoot, meta.minTier, "");
}

// Test summary:
// 1. Gets a block that doesn't exist
// 2. Gets a transition by ID & hash that doesn't exist.
Expand Down
Loading

0 comments on commit e5000b0

Please sign in to comment.