diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index dbd183d6e8..cfd836567a 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -195,14 +195,14 @@ contract TaikoL1 is EssentialContract, ITaikoL1, ITierProvider, TaikoEvents, Tai return ITierProvider(resolve("tier_provider", false)).getTier(tierId); } - /// @notice Retrieves the IDs of all supported tiers. - function getTierIds() public view virtual override returns (uint16[] memory ids) { + /// @inheritdoc ITierProvider + function getTierIds() public view override returns (uint16[] memory ids) { ids = ITierProvider(resolve("tier_provider", false)).getTierIds(); if (ids.length >= type(uint8).max) revert L1_TOO_MANY_TIERS(); } - /// @notice Determines the minimal tier for a block based on a random input. - function getMinTier(uint256 rand) public view virtual override returns (uint16) { + /// @inheritdoc ITierProvider + function getMinTier(uint256 rand) public view override returns (uint16) { return ITierProvider(resolve("tier_provider", false)).getMinTier(rand); } diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol index b7ee0fcd69..1e20d75f77 100644 --- a/packages/protocol/contracts/L1/libs/LibProving.sol +++ b/packages/protocol/contracts/L1/libs/LibProving.sol @@ -399,7 +399,7 @@ library LibProving { if (tier.contestBond == 0) return; bool inProvingWindow = uint256(ts.timestamp).max(state.slotB.lastUnpausedAt) - + tier.provingWindow >= block.timestamp; + + tier.provingWindow * 60 >= block.timestamp; bool isAssignedPover = msg.sender == blk.assignedProver; // The assigned prover can only submit the very first transition. diff --git a/packages/protocol/contracts/L1/libs/LibVerifying.sol b/packages/protocol/contracts/L1/libs/LibVerifying.sol index fc03215c01..979acbcb3e 100644 --- a/packages/protocol/contracts/L1/libs/LibVerifying.sol +++ b/packages/protocol/contracts/L1/libs/LibVerifying.sol @@ -172,7 +172,7 @@ library LibVerifying { tierProvider = resolver.resolve("tier_provider", false); } if ( - uint256(ITierProvider(tierProvider).getTier(ts.tier).cooldownWindow) + uint256(ITierProvider(tierProvider).getTier(ts.tier).cooldownWindow) * 60 + uint256(ts.timestamp).max(state.slotB.lastUnpausedAt) > block.timestamp ) { // If cooldownWindow is 0, the block can theoretically diff --git a/packages/protocol/contracts/L1/tiers/OptimisticTierProvider.sol b/packages/protocol/contracts/L1/tiers/DevnetTierProvider.sol similarity index 77% rename from packages/protocol/contracts/L1/tiers/OptimisticTierProvider.sol rename to packages/protocol/contracts/L1/tiers/DevnetTierProvider.sol index c025131593..1d6151ea73 100644 --- a/packages/protocol/contracts/L1/tiers/OptimisticTierProvider.sol +++ b/packages/protocol/contracts/L1/tiers/DevnetTierProvider.sol @@ -17,11 +17,11 @@ pragma solidity 0.8.24; import "../../common/EssentialContract.sol"; import "./ITierProvider.sol"; -contract OptimisticTierProvider is EssentialContract, ITierProvider { +/// @title DevnetTierProvider +/// @dev Labeled in AddressResolver as "tier_provider" +contract DevnetTierProvider is EssentialContract, ITierProvider { uint256[50] private __gap; - error TIER_NOT_FOUND(); - /// @notice Initializes the contract with the provided address manager. function init() external initializer { __Essential_init(); @@ -33,9 +33,9 @@ contract OptimisticTierProvider is EssentialContract, ITierProvider { verifierName: "tier_optimistic", validityBond: 250 ether, // TKO contestBond: 500 ether, // TKO - cooldownWindow: 24 hours, - provingWindow: 2 hours, - maxBlocksToVerifyPerProof: 10 + cooldownWindow: 1440, //24 hours + provingWindow: 120, // 2 hours + maxBlocksToVerifyPerProof: 16 }); } @@ -44,9 +44,9 @@ contract OptimisticTierProvider is EssentialContract, ITierProvider { verifierName: "tier_guardian", validityBond: 0, // must be 0 for top tier contestBond: 0, // must be 0 for top tier - cooldownWindow: 24 hours, - provingWindow: 8 hours, - maxBlocksToVerifyPerProof: 4 + cooldownWindow: 60, //1 hours + provingWindow: 2880, // 48 hours + maxBlocksToVerifyPerProof: 16 }); } @@ -59,7 +59,7 @@ contract OptimisticTierProvider is EssentialContract, ITierProvider { tiers[1] = LibTiers.TIER_GUARDIAN; } - function getMinTier(uint256 /*rand*/ ) public pure override returns (uint16) { + function getMinTier(uint256) public pure override returns (uint16) { return LibTiers.TIER_OPTIMISTIC; } } diff --git a/packages/protocol/contracts/L1/tiers/ITierProvider.sol b/packages/protocol/contracts/L1/tiers/ITierProvider.sol index d668c189aa..3759d4cfdc 100644 --- a/packages/protocol/contracts/L1/tiers/ITierProvider.sol +++ b/packages/protocol/contracts/L1/tiers/ITierProvider.sol @@ -21,11 +21,13 @@ interface ITierProvider { bytes32 verifierName; uint96 validityBond; uint96 contestBond; - uint24 cooldownWindow; - uint16 provingWindow; + uint24 cooldownWindow; // in minutes + uint16 provingWindow; // in minutes uint8 maxBlocksToVerifyPerProof; } + error TIER_NOT_FOUND(); + /// @dev Retrieves the configuration for a specified tier. function getTier(uint16 tierId) external view returns (Tier memory); @@ -42,5 +44,6 @@ interface ITierProvider { library LibTiers { uint16 public constant TIER_OPTIMISTIC = 100; uint16 public constant TIER_SGX = 200; + uint16 public constant TIER_SGX_ZKVM = 300; uint16 public constant TIER_GUARDIAN = 1000; } diff --git a/packages/protocol/contracts/L1/tiers/MainnetTierProvider.sol b/packages/protocol/contracts/L1/tiers/MainnetTierProvider.sol new file mode 100644 index 0000000000..414417967f --- /dev/null +++ b/packages/protocol/contracts/L1/tiers/MainnetTierProvider.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ +// +// Email: security@taiko.xyz +// Website: https://taiko.xyz +// GitHub: https://github.com/taikoxyz +// Discord: https://discord.gg/taikoxyz +// Twitter: https://twitter.com/taikoxyz +// Blog: https://mirror.xyz/labs.taiko.eth +// Youtube: https://www.youtube.com/@taikoxyz + +pragma solidity 0.8.24; + +import "../../common/EssentialContract.sol"; +import "./ITierProvider.sol"; + +/// @title MainnetTierProvider +/// @dev Labeled in AddressResolver as "tier_provider" +contract MainnetTierProvider is EssentialContract, ITierProvider { + uint256[50] private __gap; + + /// @notice Initializes the contract with the provided address manager. + function init() external initializer { + __Essential_init(); + } + + function getTier(uint16 tierId) public pure override returns (ITierProvider.Tier memory) { + if (tierId == LibTiers.TIER_SGX) { + return ITierProvider.Tier({ + verifierName: "tier_sgx", + validityBond: 250 ether, // TKO + contestBond: 500 ether, // TKO + cooldownWindow: 1440, //24 hours + provingWindow: 60, // 1 hours + maxBlocksToVerifyPerProof: 8 + }); + } + + if (tierId == LibTiers.TIER_SGX_ZKVM) { + return ITierProvider.Tier({ + verifierName: "tier_sgx_zkvm", + validityBond: 500 ether, // TKO + contestBond: 1000 ether, // TKO + cooldownWindow: 1440, //24 hours + provingWindow: 240, // 4 hours + maxBlocksToVerifyPerProof: 4 + }); + } + + if (tierId == LibTiers.TIER_GUARDIAN) { + return ITierProvider.Tier({ + verifierName: "tier_guardian", + validityBond: 0, // must be 0 for top tier + contestBond: 0, // must be 0 for top tier + cooldownWindow: 60, //1 hours + provingWindow: 2880, // 48 hours + maxBlocksToVerifyPerProof: 16 + }); + } + + revert TIER_NOT_FOUND(); + } + + function getTierIds() public pure override returns (uint16[] memory tiers) { + tiers = new uint16[](3); + tiers[0] = LibTiers.TIER_SGX; + tiers[1] = LibTiers.TIER_SGX_ZKVM; + tiers[2] = LibTiers.TIER_GUARDIAN; + } + + function getMinTier(uint256 rand) public pure override returns (uint16) { + // 0.1% require SGX + ZKVM; all others require SGX + if (rand % 1000 == 0) return LibTiers.TIER_SGX_ZKVM; + else return LibTiers.TIER_SGX; + } +} diff --git a/packages/protocol/contracts/L1/tiers/TestnetTierProvider.sol b/packages/protocol/contracts/L1/tiers/TestnetTierProvider.sol index adb5d98080..4716267e81 100644 --- a/packages/protocol/contracts/L1/tiers/TestnetTierProvider.sol +++ b/packages/protocol/contracts/L1/tiers/TestnetTierProvider.sol @@ -19,17 +19,9 @@ import "./ITierProvider.sol"; /// @title TestnetTierProvider /// @dev Labeled in AddressResolver as "tier_provider" -/// @dev Assuming liveness bound is 250TKO. -// Taiko token's total supply is 1 billion. Assuming block time is 2 second, and -// the cool down period is 2 days. In 2 days, we can have (2*86400/2)=86400 -// blocks. Assuming 10% tokens are used in bonds, then each block may use up to -// these many tokens: 1,000,000,000 * 10% / 86400=1157 TOK per block, which is -// about 722 USD. contract TestnetTierProvider is EssentialContract, ITierProvider { uint256[50] private __gap; - error TIER_NOT_FOUND(); - /// @notice Initializes the contract with the provided address manager. function init() external initializer { __Essential_init(); @@ -41,9 +33,9 @@ contract TestnetTierProvider is EssentialContract, ITierProvider { verifierName: "tier_optimistic", validityBond: 250 ether, // TKO contestBond: 500 ether, // TKO - cooldownWindow: 24 hours, - provingWindow: 2 hours, - maxBlocksToVerifyPerProof: 10 + cooldownWindow: 1440, //24 hours + provingWindow: 30, // 0.5 hours + maxBlocksToVerifyPerProof: 12 }); } @@ -52,8 +44,8 @@ contract TestnetTierProvider is EssentialContract, ITierProvider { verifierName: "tier_sgx", validityBond: 500 ether, // TKO contestBond: 1000 ether, // TKO - cooldownWindow: 24 hours, - provingWindow: 4 hours, + cooldownWindow: 1440, //24 hours + provingWindow: 60, // 1 hours maxBlocksToVerifyPerProof: 8 }); } @@ -63,9 +55,9 @@ contract TestnetTierProvider is EssentialContract, ITierProvider { verifierName: "tier_guardian", validityBond: 0, // must be 0 for top tier contestBond: 0, // must be 0 for top tier - cooldownWindow: 24 hours, - provingWindow: 8 hours, - maxBlocksToVerifyPerProof: 4 + cooldownWindow: 60, //1 hours + provingWindow: 2880, // 48 hours + maxBlocksToVerifyPerProof: 16 }); } diff --git a/packages/protocol/script/DeployOnL1.s.sol b/packages/protocol/script/DeployOnL1.s.sol index ac09cb47d2..42798fabf3 100644 --- a/packages/protocol/script/DeployOnL1.s.sol +++ b/packages/protocol/script/DeployOnL1.s.sol @@ -19,8 +19,9 @@ import "@openzeppelin/contracts/utils/Strings.sol"; import "../contracts/L1/TaikoToken.sol"; import "../contracts/L1/TaikoL1.sol"; import "../contracts/L1/provers/GuardianProver.sol"; +import "../contracts/L1/tiers/DevnetTierProvider.sol"; import "../contracts/L1/tiers/TestnetTierProvider.sol"; -import "../contracts/L1/tiers/OptimisticTierProvider.sol"; +import "../contracts/L1/tiers/MainnetTierProvider.sol"; import "../contracts/L1/hooks/AssignmentHook.sol"; import "../contracts/L1/gov/TaikoTimelockController.sol"; import "../contracts/L1/gov/TaikoGovernor.sol"; @@ -320,16 +321,9 @@ contract DeployOnL1 is DeployCapability { owner: timelock }); - address tierProvider; - if (vm.envBool("OPTIMISTIC_TIER_PROVIDER")) { - tierProvider = address(new OptimisticTierProvider()); - } else { - tierProvider = address(new TestnetTierProvider()); - } - deployProxy({ name: "tier_provider", - impl: tierProvider, + impl: deployTierProvider(vm.envString("TIER_PROVIDER")), data: abi.encodeCall(TestnetTierProvider.init, ()), registerTo: rollupAddressManager, owner: timelock @@ -380,6 +374,18 @@ contract DeployOnL1 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 TestnetTierProvider()); + } else if (keccak256(abi.encode(tierProviderName)) == keccak256(abi.encode("mainnet"))) { + return address(new MainnetTierProvider()); + } else { + revert("invalid tier provider"); + } + } + function deployAuxContracts() private { address horseToken = address(new FreeMintERC20("Horse Token", "HORSE")); console2.log("HorseToken", horseToken); diff --git a/packages/protocol/script/test_deploy_on_l1.sh b/packages/protocol/script/test_deploy_on_l1.sh index e371b2e320..27114762f9 100755 --- a/packages/protocol/script/test_deploy_on_l1.sh +++ b/packages/protocol/script/test_deploy_on_l1.sh @@ -16,7 +16,7 @@ TAIKO_TOKEN_NAME="Taiko Token Katla" \ TAIKO_TOKEN_SYMBOL=TTKOk \ SHARED_ADDRESS_MANAGER=0x0000000000000000000000000000000000000000 \ L2_GENESIS_HASH=0xee1950562d42f0da28bd4550d88886bc90894c77c9c9eaefef775d4c8223f259 \ -OPTIMISTIC_TIER_PROVIDER=false \ +TIER_PROVIDER="devnet" \ forge script script/DeployOnL1.s.sol:DeployOnL1 \ --fork-url http://localhost:8545 \ --broadcast \ diff --git a/packages/protocol/test/L1/TaikoL1.t.sol b/packages/protocol/test/L1/TaikoL1.t.sol index f5ac4fd5e3..effb2ff37b 100644 --- a/packages/protocol/test/L1/TaikoL1.t.sol +++ b/packages/protocol/test/L1/TaikoL1.t.sol @@ -57,7 +57,7 @@ contract TaikoL1Test is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); parentHash = blockHash; @@ -89,7 +89,7 @@ contract TaikoL1Test is TaikoL1TestBase { proveBlock(Bob, Bob, meta, parentHash, blockHash, stateRoot, meta.minTier, ""); vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Alice, 2); parentHash = blockHash; diff --git a/packages/protocol/test/L1/TaikoL1LibProvingWithTiers.t.sol b/packages/protocol/test/L1/TaikoL1LibProvingWithTiers.t.sol index 9c9ac00ac8..10ca0540cd 100644 --- a/packages/protocol/test/L1/TaikoL1LibProvingWithTiers.t.sol +++ b/packages/protocol/test/L1/TaikoL1LibProvingWithTiers.t.sol @@ -86,7 +86,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); @@ -128,14 +128,14 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); // Cannot verify block because it is contested.. verifyBlock(Carol, 1); proveHigherTierProof(meta, parentHash, stateRoot, blockHash, minTier); - vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow * 60 + 1); // Now can verify console2.log("Probalom verify-olni"); verifyBlock(Carol, 1); @@ -177,7 +177,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); // Cannot verify block because it is contested.. verifyBlock(Carol, 1); @@ -185,7 +185,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { proveHigherTierProof(meta, parentHash, stateRoot, blockHash, minTier); // Otherwise just not contest - vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow * 60 + 1); // Now can verify verifyBlock(Carol, 1); @@ -228,7 +228,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); // Cannot verify block because it is contested.. verifyBlock(Carol, 1); @@ -239,7 +239,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { } // Otherwise just not contest - vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow * 60 + 1); // Now can verify verifyBlock(Carol, 1); @@ -281,7 +281,9 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); - vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow + 1); + vm.warp( + block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow * 60 + 1 + ); // Cannot verify block because it is contested.. verifyBlock(Carol, 1); @@ -299,7 +301,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { } // Otherwise just not contest - vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow * 60 + 1); // Now can verify verifyBlock(Carol, 1); @@ -343,7 +345,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); parentHash = blockHash; @@ -377,7 +379,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); proveBlock( Bob, @@ -439,7 +441,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); @@ -456,7 +458,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { ); vm.roll(block.number + 15 * 12); - vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(LibTiers.TIER_GUARDIAN).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); parentHash = blockHash; @@ -505,7 +507,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); @@ -548,7 +550,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); @@ -600,7 +602,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); @@ -740,7 +742,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1); @@ -810,7 +812,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { vm.roll(block.number + 15 * 12); uint16 minTier = meta.minTier; - vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow + 1); + vm.warp(block.timestamp + L1.getTier(minTier).cooldownWindow * 60 + 1); verifyBlock(Carol, 1);