From e8ba7168231f9a8bbef1378fa93448b11c4267ac Mon Sep 17 00:00:00 2001 From: Dani <51912515+adaki2004@users.noreply.github.com> Date: Wed, 10 May 2023 05:26:35 +0200 Subject: [PATCH] feat(protocol): Introduce oracle and system prover concept (#13729) Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com> Co-authored-by: jeff <113397187+cyberhorsey@users.noreply.github.com> Co-authored-by: Daniel Wang --- .../protocol/contracts/L1/TaikoConfig.sol | 1 + packages/protocol/contracts/L1/TaikoData.sol | 3 +- .../protocol/contracts/L1/TaikoErrors.sol | 7 +- .../protocol/contracts/L1/libs/LibProving.sol | 93 +-- .../contracts/L1/libs/LibVerifying.sol | 32 +- .../contracts/common/AddressResolver.sol | 11 +- packages/protocol/script/DeployOnL1.s.sol | 2 + packages/protocol/script/test_deploy_on_l1.sh | 1 + packages/protocol/test/TaikoL1.sim.sol | 12 +- packages/protocol/test/TaikoL1.t.sol | 16 +- .../test/TaikoL1LibTokenomicsMainnet.t.sol | 12 +- .../test/TaikoL1LibTokenomicsTestnet.t.sol | 64 ++- packages/protocol/test/TaikoL1Oracle.t.sol | 528 +++++++++++++++--- packages/protocol/test/TaikoL1TestBase.t.sol | 9 +- .../contract-documentation/L1/TaikoData.md | 1 + .../contract-documentation/L1/TaikoErrors.md | 26 +- .../common/AddressResolver.md | 6 + 17 files changed, 611 insertions(+), 213 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoConfig.sol b/packages/protocol/contracts/L1/TaikoConfig.sol index 070ce1436d..53b18ac2e3 100644 --- a/packages/protocol/contracts/L1/TaikoConfig.sol +++ b/packages/protocol/contracts/L1/TaikoConfig.sol @@ -35,6 +35,7 @@ library TaikoConfig { maxBytesPerTxList: 120000, minTxGasLimit: 21000, proofCooldownPeriod: 30 minutes, + systemProofCooldownPeriod: 15 minutes, // Only need 1 real zkp per 10 blocks. // If block number is N, then only when N % 10 == 0, the real ZKP // is needed. For mainnet, this must be 0 or 1. diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index ea5fbc1562..705e702550 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -20,6 +20,7 @@ library TaikoData { uint256 minTxGasLimit; uint256 txListCacheExpiry; uint256 proofCooldownPeriod; + uint256 systemProofCooldownPeriod; uint256 realProofSkipSize; uint256 ethDepositGas; uint256 ethDepositMaxFee; @@ -93,7 +94,7 @@ library TaikoData { bytes32 blockHash; bytes32 signalRoot; uint64 provenAt; - address prover; // 0x0 to mark as 'oracle proof' + address prover; uint32 gasUsed; } diff --git a/packages/protocol/contracts/L1/TaikoErrors.sol b/packages/protocol/contracts/L1/TaikoErrors.sol index ab056969a9..a94a128bc2 100644 --- a/packages/protocol/contracts/L1/TaikoErrors.sol +++ b/packages/protocol/contracts/L1/TaikoErrors.sol @@ -19,9 +19,12 @@ abstract contract TaikoErrors { error L1_INVALID_METADATA(); error L1_INVALID_PARAM(); error L1_INVALID_PROOF(); - error L1_NOT_ORACLE_PROVER(); - error L1_ORACLE_DISABLED(); + error L1_INVALID_PROOF_OVERWRITE(); + error L1_NOT_SPECIAL_PROVER(); + error L1_ORACLE_PROVER_DISABLED(); error L1_SAME_PROOF(); + error L1_SYSTEM_PROVER_DISABLED(); + error L1_SYSTEM_PROVER_PROHIBITED(); error L1_TOO_MANY_BLOCKS(); error L1_TX_LIST_NOT_EXIST(); error L1_TX_LIST_HASH(); diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol index 3161e4b253..695c935afa 100644 --- a/packages/protocol/contracts/L1/libs/LibProving.sol +++ b/packages/protocol/contracts/L1/libs/LibProving.sol @@ -27,11 +27,14 @@ library LibProving { error L1_BLOCK_ID(); error L1_EVIDENCE_MISMATCH(bytes32 expected, bytes32 actual); error L1_FORK_CHOICE_NOT_FOUND(); - error L1_INVALID_PROOF(); error L1_INVALID_EVIDENCE(); - error L1_ORACLE_DISABLED(); - error L1_NOT_ORACLE_PROVER(); + error L1_INVALID_PROOF(); + error L1_INVALID_PROOF_OVERWRITE(); + error L1_NOT_SPECIAL_PROVER(); + error L1_ORACLE_PROVER_DISABLED(); error L1_SAME_PROOF(); + error L1_SYSTEM_PROVER_DISABLED(); + error L1_SYSTEM_PROVER_PROHIBITED(); function proveBlock( TaikoData.State storage state, @@ -60,42 +63,47 @@ library LibProving { if (blk.metaHash != evidence.metaHash) revert L1_EVIDENCE_MISMATCH(blk.metaHash, evidence.metaHash); + // Separate between oracle proof (which needs to be overwritten) + // and non-oracle but system proofs + address specialProver; if (evidence.prover == address(0)) { - address oracleProver = resolver.resolve("oracle_prover", true); - if (oracleProver == address(0)) revert L1_ORACLE_DISABLED(); - - if (msg.sender != oracleProver) { - if (evidence.proof.length != 64) { - revert L1_NOT_ORACLE_PROVER(); - } else { - uint8 v = uint8(evidence.verifierId); - bytes32 r; - bytes32 s; - bytes memory data = evidence.proof; - assembly { - r := mload(add(data, 32)) - s := mload(add(data, 64)) - } - - // clear the proof before hashing evidence - evidence.verifierId = 0; - evidence.proof = new bytes(0); - - if ( - oracleProver != - ecrecover(keccak256(abi.encode(evidence)), v, r, s) - ) revert L1_NOT_ORACLE_PROVER(); - } + specialProver = resolver.resolve("oracle_prover", true); + if (specialProver == address(0)) { + revert L1_ORACLE_PROVER_DISABLED(); + } + } else if (evidence.prover == address(1)) { + specialProver = resolver.resolve("system_prover", true); + if (specialProver == address(0)) { + revert L1_SYSTEM_PROVER_DISABLED(); } if ( - config.realProofSkipSize > 1 && - blockId % config.realProofSkipSize != 0 - ) { - // For this block, real ZKP is not necessary, so the oracle - // proof will be treated as a real proof (by setting the prover - // to a non-zero value) - evidence.prover = oracleProver; + config.realProofSkipSize <= 1 || + blockId % config.realProofSkipSize == 0 + ) revert L1_SYSTEM_PROVER_PROHIBITED(); + } + + if (specialProver != address(0) && msg.sender != specialProver) { + if (evidence.proof.length != 64) { + revert L1_NOT_SPECIAL_PROVER(); + } else { + uint8 v = uint8(evidence.verifierId); + bytes32 r; + bytes32 s; + bytes memory data = evidence.proof; + assembly { + r := mload(add(data, 32)) + s := mload(add(data, 64)) + } + + // clear the proof before hashing evidence + evidence.verifierId = 0; + evidence.proof = new bytes(0); + + if ( + specialProver != + ecrecover(keccak256(abi.encode(evidence)), v, r, s) + ) revert L1_NOT_SPECIAL_PROVER(); } } @@ -129,15 +137,24 @@ library LibProving { ] = fcId; } } else if (evidence.prover == address(0)) { + // This is the branch the oracle prover is trying to overwrite fc = blk.forkChoices[fcId]; - if ( fc.blockHash == evidence.blockHash && fc.signalRoot == evidence.signalRoot && fc.gasUsed == evidence.gasUsed ) revert L1_SAME_PROOF(); } else { - revert L1_ALREADY_PROVEN(); + // This is the branch provers trying to overwrite + fc = blk.forkChoices[fcId]; + if (fc.prover != address(0) && fc.prover != address(1)) + revert L1_ALREADY_PROVEN(); + + if ( + fc.blockHash != evidence.blockHash || + fc.signalRoot != evidence.signalRoot || + fc.gasUsed != evidence.gasUsed + ) revert L1_INVALID_PROOF_OVERWRITE(); } fc.blockHash = evidence.blockHash; @@ -146,7 +163,7 @@ library LibProving { fc.provenAt = uint64(block.timestamp); fc.prover = evidence.prover; - if (evidence.prover != address(0)) { + if (evidence.prover != address(0) && evidence.prover != address(1)) { uint256[9] memory inputs; inputs[0] = uint256( diff --git a/packages/protocol/contracts/L1/libs/LibVerifying.sol b/packages/protocol/contracts/L1/libs/LibVerifying.sol index 94afe5807c..86ab0e3ea0 100644 --- a/packages/protocol/contracts/L1/libs/LibVerifying.sol +++ b/packages/protocol/contracts/L1/libs/LibVerifying.sol @@ -56,7 +56,6 @@ library LibVerifying { config.proofTimeTarget == 0 || config.adjustmentQuotient == 0 ) revert L1_INVALID_CONFIG(); - uint64 timeNow = uint64(block.timestamp); state.genesisHeight = uint64(block.number); state.genesisTimestamp = timeNow; @@ -97,8 +96,7 @@ library LibVerifying { ++i; } - address oracleProver = resolver.resolve("oracle_prover", true); - + address systemProver = resolver.resolve("system_prover", true); while (i < state.numBlocks && processed < maxBlocks) { blk = state.blocks[i % config.ringBufferSize]; assert(blk.blockId == i); @@ -111,9 +109,8 @@ library LibVerifying { if (fc.prover == address(0)) break; - uint256 proofCooldownPeriod = oracleProver == address(0) || - fc.prover == oracleProver - ? 0 + uint256 proofCooldownPeriod = fc.prover == address(1) + ? config.systemProofCooldownPeriod : config.proofCooldownPeriod; if (block.timestamp < fc.provenAt + proofCooldownPeriod) break; @@ -127,7 +124,8 @@ library LibVerifying { config: config, blk: blk, fcId: uint24(fcId), - fc: fc + fc: fc, + systemProver: systemProver }); unchecked { @@ -161,7 +159,8 @@ library LibVerifying { TaikoData.Config memory config, TaikoData.Block storage blk, TaikoData.ForkChoice storage fc, - uint24 fcId + uint24 fcId, + address systemProver ) private { uint64 proofTime; unchecked { @@ -180,12 +179,17 @@ library LibVerifying { // reward the prover if (reward != 0) { - if (state.taikoTokenBalances[fc.prover] == 0) { - // Reduce refund to 1 wei as a penalty if the proposer - // has 0 TKO outstanding balance. - state.taikoTokenBalances[fc.prover] = 1; - } else { - state.taikoTokenBalances[fc.prover] += reward; + address prover = fc.prover != address(1) ? fc.prover : systemProver; + + // systemProver may become address(0) after a block is proven + if (prover != address(0)) { + if (state.taikoTokenBalances[prover] == 0) { + // Reduce refund to 1 wei as a penalty if the proposer + // has 0 TKO outstanding balance. + state.taikoTokenBalances[prover] = 1; + } else { + state.taikoTokenBalances[prover] += reward; + } } } diff --git a/packages/protocol/contracts/common/AddressResolver.sol b/packages/protocol/contracts/common/AddressResolver.sol index ec2d862386..655cd307fa 100644 --- a/packages/protocol/contracts/common/AddressResolver.sol +++ b/packages/protocol/contracts/common/AddressResolver.sol @@ -22,6 +22,7 @@ abstract contract AddressResolver { error RESOLVER_DENIED(); error RESOLVER_INVALID_ADDR(); + error RESOLVER_ZERO_ADDR(uint256 chainId, bytes32 name); modifier onlyFromNamed(bytes32 name) { if (msg.sender != resolve(name, false)) revert RESOLVER_DENIED(); @@ -81,13 +82,7 @@ abstract contract AddressResolver { ) private view returns (address payable addr) { addr = payable(_addressManager.getAddress(chainId, name)); - if (!allowZeroAddress) { - // We do not use custom error so this string-based - // error message is more helpful for diagnosis. - require( - addr != address(0), - string(abi.encode("AR:zeroAddr:", chainId, ".", name)) - ); - } + if (!allowZeroAddress && addr == address(0)) + revert RESOLVER_ZERO_ADDR(chainId, name); } } diff --git a/packages/protocol/script/DeployOnL1.s.sol b/packages/protocol/script/DeployOnL1.s.sol index 4c36c8e796..3fda9c8556 100644 --- a/packages/protocol/script/DeployOnL1.s.sol +++ b/packages/protocol/script/DeployOnL1.s.sol @@ -34,6 +34,7 @@ contract DeployOnL1 is Script { address public owner = vm.envAddress("OWNER"); address public oracleProver = vm.envAddress("ORACLE_PROVER"); + address public systemProver = vm.envAddress("SYSTEM_PROVER"); address public sharedSignalService = vm.envAddress("SHARED_SIGNAL_SERVICE"); @@ -86,6 +87,7 @@ contract DeployOnL1 is Script { setAddress(l2ChainId, "taiko", taikoL2Address); setAddress(l2ChainId, "signal_service", l2SignalService); setAddress("oracle_prover", oracleProver); + setAddress("system_prover", systemProver); setAddress(l2ChainId, "treasure", treasure); // TaikoToken diff --git a/packages/protocol/script/test_deploy_on_l1.sh b/packages/protocol/script/test_deploy_on_l1.sh index 2ee979d358..28bbb97f14 100755 --- a/packages/protocol/script/test_deploy_on_l1.sh +++ b/packages/protocol/script/test_deploy_on_l1.sh @@ -6,6 +6,7 @@ set -e PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ SHARED_SIGNAL_SERVICE=0x0000000000000000000000000000000000000000 \ ORACLE_PROVER=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 \ +SYSTEM_PROVER=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 \ OWNER=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 \ TAIKO_L2_ADDRESS=0x0000777700000000000000000000000000000001 \ L2_SIGNAL_SERVICE=0x0000777700000000000000000000000000000007 \ diff --git a/packages/protocol/test/TaikoL1.sim.sol b/packages/protocol/test/TaikoL1.sim.sol index 7acf183d53..eb4468e58e 100644 --- a/packages/protocol/test/TaikoL1.sim.sol +++ b/packages/protocol/test/TaikoL1.sim.sol @@ -308,14 +308,14 @@ contract TaikoL1Simulation is TaikoL1TestBase { ]; proveBlock( + Bob, Bob, metas[blockId], parentHashes[blockId], parentGasUsed[blockId], gasUsed[blockId], blockHashes[blockId], - signalRoots[blockId], - false + signalRoots[blockId] ); } } @@ -552,14 +552,14 @@ contract TaikoL1Simulation is TaikoL1TestBase { ]; proveBlock( + Bob, Bob, metas[blockId], parentHashes[blockId], parentGasUsed[blockId], gasUsed[blockId], blockHashes[blockId], - signalRoots[blockId], - false + signalRoots[blockId] ); } } @@ -801,14 +801,14 @@ contract TaikoL1Simulation is TaikoL1TestBase { ]; proveBlock( + Bob, Bob, metas[blockId], parentHashes[blockId], parentGasUsed[blockId], gasUsed[blockId], blockHashes[blockId], - signalRoots[blockId], - false + signalRoots[blockId] ); } } diff --git a/packages/protocol/test/TaikoL1.t.sol b/packages/protocol/test/TaikoL1.t.sol index 81524b9335..0fe30869d3 100644 --- a/packages/protocol/test/TaikoL1.t.sol +++ b/packages/protocol/test/TaikoL1.t.sol @@ -73,14 +73,14 @@ contract TaikoL1Test is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, parentGasUsed, gasUsed, blockHash, - signalRoot, - false + signalRoot ); verifyBlock(Carol, 1); @@ -111,14 +111,14 @@ contract TaikoL1Test is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Alice, Alice, meta, parentHash, parentGasUsed, gasUsed, blockHash, - signalRoot, - false + signalRoot ); verifyBlock(Alice, 2); parentHash = blockHash; @@ -151,14 +151,14 @@ contract TaikoL1Test is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Alice, Alice, meta, parentHash, parentGasUsed, gasUsed, blockHash, - signalRoot, - false + signalRoot ); parentHash = blockHash; parentGasUsed = gasUsed; @@ -266,14 +266,14 @@ contract TaikoL1Test is TaikoL1TestBase { signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHashes[blockId - 1], blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); verifyBlock(Carol, 1); diff --git a/packages/protocol/test/TaikoL1LibTokenomicsMainnet.t.sol b/packages/protocol/test/TaikoL1LibTokenomicsMainnet.t.sol index e43e166d25..0e2867ebca 100644 --- a/packages/protocol/test/TaikoL1LibTokenomicsMainnet.t.sol +++ b/packages/protocol/test/TaikoL1LibTokenomicsMainnet.t.sol @@ -108,14 +108,14 @@ contract TaikoL1LibTokenomicsMainnet is TaikoL1TestBase { if (blockId > proofTime) { //Start proving with an offset proveBlock( + Bob, Bob, meta[blockId - proofTime], parentHashes[blockId - proofTime], (blockId - proofTime == 1) ? 0 : 1000000, // Genesis block has 0 gas used 1000000, blockHashes[blockId - proofTime], - signalRoots[blockId - proofTime], - false + signalRoots[blockId - proofTime] ); uint64 provenAt = uint64(block.timestamp); @@ -177,14 +177,14 @@ contract TaikoL1LibTokenomicsMainnet is TaikoL1TestBase { if (blockId > proofTime) { //Start proving with an offset proveBlock( + Bob, Bob, meta[blockId - proofTime], parentHashes[blockId - proofTime], (blockId - proofTime == 1) ? 0 : 1000000, 1000000, blockHashes[blockId - proofTime], - signalRoots[blockId - proofTime], - false + signalRoots[blockId - proofTime] ); uint64 provenAt = uint64(block.timestamp); @@ -250,14 +250,14 @@ contract TaikoL1LibTokenomicsMainnet is TaikoL1TestBase { if (blockId > proofTime) { //Start proving with an offset proveBlock( + Bob, Bob, meta[blockId - proofTime], parentHashes[blockId - proofTime], (blockId - proofTime == 1) ? 0 : 1000000, 1000000, blockHashes[blockId - proofTime], - signalRoots[blockId - proofTime], - false + signalRoots[blockId - proofTime] ); uint64 provenAt = uint64(block.timestamp); diff --git a/packages/protocol/test/TaikoL1LibTokenomicsTestnet.t.sol b/packages/protocol/test/TaikoL1LibTokenomicsTestnet.t.sol index dd390dac0d..e94be00fc2 100644 --- a/packages/protocol/test/TaikoL1LibTokenomicsTestnet.t.sol +++ b/packages/protocol/test/TaikoL1LibTokenomicsTestnet.t.sol @@ -86,14 +86,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -132,14 +132,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -166,7 +166,6 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { { mine(1); //Needs lot of token here - because there is lots of time elapsed between 2 'propose' blocks, which will raise the fee - depositTaikoToken(Alice, 1E8 * 1E8, 100 ether); depositTaikoToken(Bob, 1E8 * 1E8, 100 ether); depositTaikoToken(Carol, 1E8 * 1E8, 100 ether); @@ -202,14 +201,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, metas[blockId], parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -244,14 +243,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -307,14 +306,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -378,14 +377,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta[blockId], parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); @@ -451,14 +450,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta[blockId], parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); @@ -515,14 +514,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -551,6 +550,7 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { external { mine(1); + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); @@ -586,14 +586,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta[blockId], parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); @@ -651,14 +651,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -696,14 +696,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -760,14 +760,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, metaArr[blockId], parentHash, (blockId == 1 ? 0 : 1000000), 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); @@ -805,14 +805,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -838,9 +838,11 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { external { mine(1); + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); + bytes32 parentHash = GENESIS_BLOCK_HASH; // Check balances @@ -865,14 +867,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, blockId == 1 ? 0 : 1000000, 1000000, blockHash, - signalRoot, - false + signalRoot ); uint64 provenAt = uint64(block.timestamp); console2.log( @@ -929,14 +931,14 @@ contract TaikoL1LibTokenomicsTestnet is TaikoL1TestBase { if (blockId > proofTime) { //Start proving with an offset proveBlock( + Bob, Bob, meta[blockId - proofTime], parentHashes[blockId - proofTime], (blockId - proofTime == 1) ? 0 : 1000000, 1000000, blockHashes[blockId - proofTime], - signalRoots[blockId - proofTime], - false + signalRoots[blockId - proofTime] ); uint64 provenAt = uint64(block.timestamp); diff --git a/packages/protocol/test/TaikoL1Oracle.t.sol b/packages/protocol/test/TaikoL1Oracle.t.sol index 4d6c30ad59..634661e245 100644 --- a/packages/protocol/test/TaikoL1Oracle.t.sol +++ b/packages/protocol/test/TaikoL1Oracle.t.sol @@ -28,7 +28,7 @@ contract TaikoL1Oracle is TaikoL1 { config.maxNumProposedBlocks = 10; config.ringBufferSize = 12; config.proofCooldownPeriod = 5 minutes; - config.realProofSkipSize = 0; + config.realProofSkipSize = 10; } } @@ -47,6 +47,7 @@ contract TaikoL1OracleTest is TaikoL1TestBase { TaikoL1TestBase.setUp(); registerAddress(L1.getVerifierName(100), address(new Verifier())); registerAddress("oracle_prover", Alice); + registerAddress("system_prover", Alice); } function testOracleProverWithSignature() external { @@ -55,16 +56,15 @@ contract TaikoL1OracleTest is TaikoL1TestBase { TaikoData.BlockMetadata memory meta = proposeBlock(Bob, 1000000, 1024); proveBlock( + Bob, Bob, meta, GENESIS_BLOCK_HASH, 10000, 10001, bytes32(uint256(0x11)), - bytes32(uint256(0x12)), - false + bytes32(uint256(0x12)) ); - TaikoData.BlockEvidence memory evidence = TaikoData.BlockEvidence({ metaHash: LibUtils.hashMetadata(meta), parentHash: GENESIS_BLOCK_HASH, @@ -77,7 +77,6 @@ contract TaikoL1OracleTest is TaikoL1TestBase { verifierId: 0, proof: new bytes(0) }); - (uint8 v, bytes32 r, bytes32 s) = vm.sign( AlicePK, keccak256(abi.encode(evidence)) @@ -88,7 +87,6 @@ contract TaikoL1OracleTest is TaikoL1TestBase { vm.prank(Carol, Carol); L1.proveBlock(meta.id, abi.encode(evidence)); - TaikoData.ForkChoice memory fc = L1.getForkChoice( 1, GENESIS_BLOCK_HASH, @@ -103,6 +101,10 @@ contract TaikoL1OracleTest is TaikoL1TestBase { } function testOracleProverCanAlwaysOverwriteIfNotSameProof() external { + // Carol is the oracle prover + registerAddress("oracle_prover", Carol); + registerAddress("system_prover", Carol); + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); @@ -120,16 +122,18 @@ contract TaikoL1OracleTest is TaikoL1TestBase { // Bob proves the block proveBlock( + Bob, Bob, meta, parentHash, parentGasUsed, 10001, bytes32(uint256(0x11)), - bytes32(uint256(0x12)), - false + bytes32(uint256(0x12)) ); + uint256 provenAt = block.timestamp; + TaikoData.ForkChoice memory fc = L1.getForkChoice( blockId, parentHash, @@ -143,51 +147,24 @@ contract TaikoL1OracleTest is TaikoL1TestBase { } assertEq(fc.blockHash, bytes32(uint256(0x11))); assertEq(fc.signalRoot, bytes32(uint256(0x12))); - assertEq(fc.provenAt, block.timestamp); + assertEq(fc.provenAt, provenAt); assertEq(fc.prover, Bob); assertEq(fc.gasUsed, 10001); - // Carol cannot prove the fork choice again + // Carol - who is oracle prover - can overwrite with same proof vm.warp(block.timestamp + 10 seconds); - vm.expectRevert(); proveBlock( Carol, + address(0), meta, parentHash, parentGasUsed, 10002, - bytes32(uint256(0x21)), - bytes32(uint256(0x22)), - false + bytes32(uint256(0x11)), + bytes32(uint256(0x12)) ); - // Alice, the oracle prover, cannot prove the fork choice again - // as a normal prover. - vm.warp(block.timestamp + 10 seconds); - vm.expectRevert(); - proveBlock( - Alice, - meta, - parentHash, - parentGasUsed, - 10003, - bytes32(uint256(0x31)), - bytes32(uint256(0x32)), - false - ); - - // Alice, the oracle prover, cannot oracle-prove the fork choice - vm.warp(block.timestamp + 10 seconds); - proveBlock( - Alice, - meta, - parentHash, - parentGasUsed, - 10003, - bytes32(uint256(0x31)), - bytes32(uint256(0x32)), - true - ); + provenAt = block.timestamp; fc = L1.getForkChoice(blockId, parentHash, parentGasUsed); @@ -196,44 +173,15 @@ contract TaikoL1OracleTest is TaikoL1TestBase { } else { assertEq(fc.key, 0); } - assertEq(fc.blockHash, bytes32(uint256(0x31))); - assertEq(fc.signalRoot, bytes32(uint256(0x32))); - assertEq(fc.provenAt, block.timestamp); - assertEq(fc.prover, address(0)); - assertEq(fc.gasUsed, 10003); - - // Alice, the oracle prover, cannot oracle-prove the fork choice multiple times - vm.warp(block.timestamp + 10 seconds); - - proveBlock( - Alice, - meta, - parentHash, - parentGasUsed, - 10004, - bytes32(uint256(0x41)), - bytes32(uint256(0x42)), - true - ); - - fc = L1.getForkChoice(blockId, parentHash, parentGasUsed); - - if (i == 0) { - assertFalse(fc.key == 0); - } else { - assertEq(fc.key, 0); - } - assertEq(fc.blockHash, bytes32(uint256(0x41))); - assertEq(fc.signalRoot, bytes32(uint256(0x42))); - assertEq(fc.provenAt, block.timestamp); + assertEq(fc.blockHash, bytes32(uint256(0x11))); + assertEq(fc.signalRoot, bytes32(uint256(0x12))); + assertEq(fc.provenAt, provenAt); assertEq(fc.prover, address(0)); - assertEq(fc.gasUsed, 10004); + assertEq(fc.gasUsed, 10002); } } function testOracleProverCannotOverwriteIfSameProof() external { - registerAddress("oracle_prover", Carol); - depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); @@ -251,16 +199,18 @@ contract TaikoL1OracleTest is TaikoL1TestBase { // Bob proves the block proveBlock( + Bob, Bob, meta, parentHash, parentGasUsed, 10001, bytes32(uint256(0x11)), - bytes32(uint256(0x12)), - false + bytes32(uint256(0x12)) ); + uint256 provenAt = block.timestamp; + TaikoData.ForkChoice memory fc = L1.getForkChoice( blockId, parentHash, @@ -274,23 +224,55 @@ contract TaikoL1OracleTest is TaikoL1TestBase { } assertEq(fc.blockHash, bytes32(uint256(0x11))); assertEq(fc.signalRoot, bytes32(uint256(0x12))); - assertEq(fc.provenAt, block.timestamp); + assertEq(fc.provenAt, provenAt); assertEq(fc.prover, Bob); assertEq(fc.gasUsed, 10001); - // Carol - who is oracle prover - cannot override with same proof + // Carol cannot prove the fork choice again vm.warp(block.timestamp + 10 seconds); - vm.expectRevert(TaikoErrors.L1_SAME_PROOF.selector); + vm.expectRevert(); proveBlock( Carol, + Carol, + meta, + parentHash, + parentGasUsed, + 10002, + bytes32(uint256(0x21)), + bytes32(uint256(0x22)) + ); + + // Alice, the oracle prover, cannot overwrite with same parameters + vm.warp(block.timestamp + 10 seconds); + + vm.expectRevert(TaikoErrors.L1_SAME_PROOF.selector); + proveBlock( + Alice, + address(0), meta, parentHash, parentGasUsed, 10001, bytes32(uint256(0x11)), - bytes32(uint256(0x12)), - true + bytes32(uint256(0x12)) ); + + verifyBlock(Carol, 1); + + fc = L1.getForkChoice(blockId, parentHash, parentGasUsed); + + if (i == 0) { + assertFalse(fc.key == 0); + } else { + assertEq(fc.key, 0); + } + assertEq(fc.blockHash, bytes32(uint256(0x11))); + assertEq(fc.signalRoot, bytes32(uint256(0x12))); + assertEq(fc.provenAt, provenAt); + assertEq(fc.prover, Bob); + assertEq(fc.gasUsed, 10001); + + vm.warp(block.timestamp + 10 seconds); } } @@ -321,14 +303,14 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, parentGasUsed, gasUsed, blockHash, - signalRoot, - false + signalRoot ); uint256 lastVerifiedBlockId = L1 @@ -356,9 +338,15 @@ contract TaikoL1OracleTest is TaikoL1TestBase { printVariables(""); } - /// @dev Test we can verify without cooling time if the oracle prover is set to address (0) - function test_if_oracle_is_address_zero_cooldown_is_zero() external { + /// @dev So in case we have regular proving mechanism we shall check if still a cooldown happens + /// @dev when proving a block (in a normal way). + /// @notice In case both oracle_prover and system_prover is disbaled, there is no reason why + /// @notice cooldowns be above 0 min tho (!). + function test_if_oracle_is_disabled_cooldown_is_still_as_proofCooldownPeriod() + external + { registerAddress("oracle_prover", address(0)); + registerAddress("system_prover", address(0)); depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); @@ -384,14 +372,14 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 blockHash = bytes32(1E10 + blockId); bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( + Bob, Bob, meta, parentHash, parentGasUsed, gasUsed, blockHash, - signalRoot, - false + signalRoot ); uint256 lastVerifiedBlockId = L1 @@ -407,6 +395,13 @@ contract TaikoL1OracleTest is TaikoL1TestBase { .getStateVariables() .lastVerifiedBlockId; + assertEq(lastVerifiedBlockIdNow, lastVerifiedBlockId); + + vm.warp(block.timestamp + 5 minutes); + verifyBlock(Carol, 1); + + lastVerifiedBlockIdNow = L1.getStateVariables().lastVerifiedBlockId; + assertFalse(lastVerifiedBlockIdNow == lastVerifiedBlockId); parentHash = blockHash; @@ -415,9 +410,13 @@ contract TaikoL1OracleTest is TaikoL1TestBase { printVariables(""); } - /// @dev Test we can verify without cooling time if provers is oracle - function test_if_fk_prover_is_oracle_prover_cooldown_is_zero() external { + /// @dev Test if oracle prover is the only prover it cannot be verified + function test_that_simple_oracle_prover_cannot_be_verified_only_if_normal_proof_comes_in() + external + { + // Bob is an oracle prover now registerAddress("oracle_prover", Bob); + registerAddress("system_prover", Bob); depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); @@ -444,13 +443,13 @@ contract TaikoL1OracleTest is TaikoL1TestBase { bytes32 signalRoot = bytes32(1E9 + blockId); proveBlock( Bob, + address(0), meta, parentHash, parentGasUsed, gasUsed, blockHash, - signalRoot, - false + signalRoot ); uint256 lastVerifiedBlockId = L1 @@ -460,6 +459,353 @@ contract TaikoL1OracleTest is TaikoL1TestBase { vm.warp(block.timestamp + 1 seconds); verifyBlock(Carol, 1); + // Check if shortly after proving (+verify) the last verify is the same (bc it is an oracle proof) + uint256 lastVerifiedBlockIdNow = L1 + .getStateVariables() + .lastVerifiedBlockId; + + // Cannot be verified + assertEq(lastVerifiedBlockIdNow, lastVerifiedBlockId); + + proveBlock( + Carol, + Carol, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + + vm.warp(block.timestamp + 1 seconds); + vm.warp(block.timestamp + 5 minutes); + verifyBlock(Carol, 1); + + lastVerifiedBlockIdNow = L1.getStateVariables().lastVerifiedBlockId; + + // Can be verified now bc regular user overwrote it + assertFalse(lastVerifiedBlockIdNow == lastVerifiedBlockId); + + parentHash = blockHash; + parentGasUsed = gasUsed; + } + printVariables(""); + } + + /// @dev Test if system prover is the prover, cooldown is systemProofCooldownPeriod + function test_if_prover_is_system_prover_cooldown_is_systemProofCooldownPeriod() + external + { + registerAddress("system_prover", Bob); + + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); + depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); + depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); + + bytes32 parentHash = GENESIS_BLOCK_HASH; + uint32 parentGasUsed = 0; + uint32 gasUsed = 1000000; + + for ( + uint256 blockId = 1; + blockId < conf.maxNumProposedBlocks * 10; + blockId++ + ) { + TaikoData.BlockMetadata memory meta = proposeBlock( + Alice, + 1000000, + 1024 + ); + printVariables("after propose"); + mine(1); + + bytes32 blockHash = bytes32(1E10 + blockId); + bytes32 signalRoot = bytes32(1E9 + blockId); + + uint256 realproof = blockId % conf.realProofSkipSize; + + if (realproof == 0) { + proveBlock( + Carol, + Carol, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + } else { + proveBlock( + Bob, + address(1), + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + } + + uint256 lastVerifiedBlockId = L1 + .getStateVariables() + .lastVerifiedBlockId; + + vm.warp(block.timestamp + 1 seconds); + verifyBlock(Carol, 1); + + // Check if shortly after proving (+verify) the last verify is not the same anymore + // no need to have a cooldown period + uint256 lastVerifiedBlockIdNow = L1 + .getStateVariables() + .lastVerifiedBlockId; + + // It would be true anyways, but better to separate things. + // If not real proof is necessary, also the proofCooldownPeriod needs to be elapsed to be true. + // So separating the check. + /// @notice: In case both system and oracle are disabled, we should set the cooldown time to 0 mins. + if (realproof != 0) + assertEq(lastVerifiedBlockIdNow, lastVerifiedBlockId); + + vm.warp(block.timestamp + conf.systemProofCooldownPeriod); + verifyBlock(Carol, 1); + + lastVerifiedBlockIdNow = L1.getStateVariables().lastVerifiedBlockId; + + assertFalse(lastVerifiedBlockIdNow == lastVerifiedBlockId); + + parentHash = blockHash; + parentGasUsed = gasUsed; + } + printVariables(""); + } + + /// @dev Test if system proofs can be verified + function test_if_system_proofs_can_be_verified_without_regular_proofs() + external + { + registerAddress("system_prover", Bob); + + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); + depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); + depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); + + bytes32 parentHash = GENESIS_BLOCK_HASH; + uint32 parentGasUsed = 0; + uint32 gasUsed = 1000000; + + for ( + uint256 blockId = 1; + blockId < conf.maxNumProposedBlocks * 10; + blockId++ + ) { + TaikoData.BlockMetadata memory meta = proposeBlock( + Alice, + 1000000, + 1024 + ); + printVariables("after propose"); + mine(1); + + bytes32 blockHash = bytes32(1E10 + blockId); + bytes32 signalRoot = bytes32(1E9 + blockId); + proveBlock( + Bob, + Bob, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + + uint256 lastVerifiedBlockId = L1 + .getStateVariables() + .lastVerifiedBlockId; + + // Need to wait config.systemProofCooldownPeriod + vm.warp(block.timestamp + conf.systemProofCooldownPeriod); + verifyBlock(Carol, 1); + + // Check if shortly after proving (+verify) the last verify is not the same anymore + // no need to have a cooldown period + uint256 lastVerifiedBlockIdNow = L1 + .getStateVariables() + .lastVerifiedBlockId; + + assertFalse(lastVerifiedBlockIdNow == lastVerifiedBlockId); + + parentHash = blockHash; + parentGasUsed = gasUsed; + } + printVariables(""); + } + + /// @dev Test if system prover cannot be overwritten + function test_if_systemProver_can_prove_but_regular_provers_can_overwrite() + external + { + registerAddress("system_prover", Bob); + + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); + depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); + depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); + + bytes32 parentHash = GENESIS_BLOCK_HASH; + uint32 parentGasUsed = 0; + uint32 gasUsed = 1000000; + + for ( + uint256 blockId = 1; + blockId < conf.maxNumProposedBlocks * 10; + blockId++ + ) { + TaikoData.BlockMetadata memory meta = proposeBlock( + Alice, + 1000000, + 1024 + ); + printVariables("after propose"); + mine(1); + + bytes32 blockHash = bytes32(1E10 + blockId); + bytes32 signalRoot = bytes32(1E9 + blockId); + + uint256 realProof = blockId % conf.realProofSkipSize; + + if (realProof == 0) { + proveBlock( + Carol, + Carol, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + } else { + proveBlock( + Bob, + address(1), + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + } + + uint256 lastVerifiedBlockId = L1 + .getStateVariables() + .lastVerifiedBlockId; + + // Carol could overwrite it + if (realProof != 0) { + proveBlock( + Carol, + Carol, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + } + + vm.warp(block.timestamp + 1 seconds); + vm.warp(block.timestamp + 5 minutes); + + TaikoData.ForkChoice memory fc = L1.getForkChoice( + blockId, + parentHash, + parentGasUsed + ); + + if (realProof != 0) assertEq(fc.prover, Carol); + + verifyBlock(Carol, 1); + + // Check if shortly after proving (+verify) the last verify is not the same anymore + // no need to have a cooldown period + uint256 lastVerifiedBlockIdNow = L1 + .getStateVariables() + .lastVerifiedBlockId; + + assertFalse(lastVerifiedBlockIdNow == lastVerifiedBlockId); + + parentHash = blockHash; + parentGasUsed = gasUsed; + } + printVariables(""); + } + + /// @dev Test if there is no system/oracle proofs + function test_if_there_is_no_system_and_oracle_provers() external { + registerAddress("system_prover", address(0)); + registerAddress("oracle_prover", address(0)); + + depositTaikoToken(Alice, 1E6 * 1E8, 100 ether); + depositTaikoToken(Bob, 1E6 * 1E8, 100 ether); + depositTaikoToken(Carol, 1E6 * 1E8, 100 ether); + + bytes32 parentHash = GENESIS_BLOCK_HASH; + uint32 parentGasUsed = 0; + uint32 gasUsed = 1000000; + + for ( + uint256 blockId = 1; + blockId < conf.maxNumProposedBlocks * 10; + blockId++ + ) { + TaikoData.BlockMetadata memory meta = proposeBlock( + Alice, + 1000000, + 1024 + ); + printVariables("after propose"); + mine(1); + + bytes32 blockHash = bytes32(1E10 + blockId); + bytes32 signalRoot = bytes32(1E9 + blockId); + proveBlock( + Bob, + Bob, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + + uint256 lastVerifiedBlockId = L1 + .getStateVariables() + .lastVerifiedBlockId; + + // Carol could not overwrite it + vm.expectRevert(TaikoErrors.L1_ALREADY_PROVEN.selector); + proveBlock( + Carol, + Carol, + meta, + parentHash, + parentGasUsed, + gasUsed, + blockHash, + signalRoot + ); + + /// @notice: Based on the current codebase we still need to wait even if the system and oracle proofs are disbaled, which + /// @notice: in such case best to set 0 mins (cause noone could overwrite a valid fk). + vm.warp(block.timestamp + conf.proofCooldownPeriod); + verifyBlock(Carol, 1); + // Check if shortly after proving (+verify) the last verify is not the same anymore // no need to have a cooldown period uint256 lastVerifiedBlockIdNow = L1 diff --git a/packages/protocol/test/TaikoL1TestBase.t.sol b/packages/protocol/test/TaikoL1TestBase.t.sol index 4cb69077ef..f7a4e39ba3 100644 --- a/packages/protocol/test/TaikoL1TestBase.t.sol +++ b/packages/protocol/test/TaikoL1TestBase.t.sol @@ -71,6 +71,7 @@ abstract contract TaikoL1TestBase is Test { registerL2Address("signal_service", address(L2SS)); registerL2Address("taiko_l2", address(TaikoL2)); registerAddress(L1.getVerifierName(100), address(new Verifier())); + registerAddress(L1.getVerifierName(0), address(new Verifier())); tko = new TaikoToken(); registerAddress("taiko_token", address(tko)); @@ -139,14 +140,14 @@ abstract contract TaikoL1TestBase is Test { } function proveBlock( + address msgSender, address prover, TaikoData.BlockMetadata memory meta, bytes32 parentHash, uint32 parentGasUsed, uint32 gasUsed, bytes32 blockHash, - bytes32 signalRoot, - bool oracle + bytes32 signalRoot ) internal { TaikoData.BlockEvidence memory evidence = TaikoData.BlockEvidence({ metaHash: LibUtils.hashMetadata(meta), @@ -154,14 +155,14 @@ abstract contract TaikoL1TestBase is Test { blockHash: blockHash, signalRoot: signalRoot, graffiti: 0x0, - prover: oracle ? address(0) : prover, + prover: prover, parentGasUsed: parentGasUsed, gasUsed: gasUsed, verifierId: 100, proof: new bytes(100) }); - vm.prank(prover, prover); + vm.prank(msgSender, msgSender); L1.proveBlock(meta.id, abi.encode(evidence)); } diff --git a/packages/website/pages/docs/reference/contract-documentation/L1/TaikoData.md b/packages/website/pages/docs/reference/contract-documentation/L1/TaikoData.md index bf10ad089a..2466466cb4 100644 --- a/packages/website/pages/docs/reference/contract-documentation/L1/TaikoData.md +++ b/packages/website/pages/docs/reference/contract-documentation/L1/TaikoData.md @@ -18,6 +18,7 @@ struct Config { uint256 minTxGasLimit; uint256 txListCacheExpiry; uint256 proofCooldownPeriod; + uint256 systemProofCooldownPeriod; uint256 realProofSkipSize; uint256 ethDepositGas; uint256 ethDepositMaxFee; diff --git a/packages/website/pages/docs/reference/contract-documentation/L1/TaikoErrors.md b/packages/website/pages/docs/reference/contract-documentation/L1/TaikoErrors.md index e0878497b7..85b66c7b9c 100644 --- a/packages/website/pages/docs/reference/contract-documentation/L1/TaikoErrors.md +++ b/packages/website/pages/docs/reference/contract-documentation/L1/TaikoErrors.md @@ -70,16 +70,22 @@ error L1_INVALID_PARAM() error L1_INVALID_PROOF() ``` -### L1_NOT_ORACLE_PROVER +### L1_INVALID_PROOF_OVERWRITE ```solidity -error L1_NOT_ORACLE_PROVER() +error L1_INVALID_PROOF_OVERWRITE() ``` -### L1_ORACLE_DISABLED +### L1_NOT_SPECIAL_PROVER ```solidity -error L1_ORACLE_DISABLED() +error L1_NOT_SPECIAL_PROVER() +``` + +### L1_ORACLE_PROVER_DISABLED + +```solidity +error L1_ORACLE_PROVER_DISABLED() ``` ### L1_SAME_PROOF @@ -88,6 +94,18 @@ error L1_ORACLE_DISABLED() error L1_SAME_PROOF() ``` +### L1_SYSTEM_PROVER_DISABLED + +```solidity +error L1_SYSTEM_PROVER_DISABLED() +``` + +### L1_SYSTEM_PROVER_PROHIBITED + +```solidity +error L1_SYSTEM_PROVER_PROHIBITED() +``` + ### L1_TOO_MANY_BLOCKS ```solidity diff --git a/packages/website/pages/docs/reference/contract-documentation/common/AddressResolver.md b/packages/website/pages/docs/reference/contract-documentation/common/AddressResolver.md index cc43712df4..7055db9fe8 100644 --- a/packages/website/pages/docs/reference/contract-documentation/common/AddressResolver.md +++ b/packages/website/pages/docs/reference/contract-documentation/common/AddressResolver.md @@ -25,6 +25,12 @@ error RESOLVER_DENIED() error RESOLVER_INVALID_ADDR() ``` +### RESOLVER_ZERO_ADDR + +```solidity +error RESOLVER_ZERO_ADDR(uint256 chainId, bytes32 name) +``` + ### onlyFromNamed ```solidity