Skip to content

Commit

Permalink
feat: block timelocked multisig during liveness disruption (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnshuJalan authored Feb 5, 2025
1 parent ac4ce00 commit 19af3fe
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 3 deletions.
5 changes: 5 additions & 0 deletions packages/protocol/contracts/layer1/based/ITaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ interface ITaikoL1 {
/// @return The prover's address. If the block is not verified yet, address(0) will be returned.
function getVerifiedBlockProver(uint64 _blockId) external view returns (address);

/// @notice Returns the timestamp of the last verification.
/// @return The timestamp of the last verification.
// Surge: Returns `lastVerificationTimestamp` added as stage-2 requirements for surge
function getLastVerificationTimestamp() external view returns(uint256);

/// @notice Gets the configuration of the TaikoL1 contract.
/// @return Config struct containing configuration parameters.
// Surge: switch to `view` to allow for dynamic chainid
Expand Down
3 changes: 3 additions & 0 deletions packages/protocol/contracts/layer1/based/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ library LibVerifying {
}

if (local.numBlocksVerified != 0) {
// Surge: Update last verification timestamp if a block has been verified
_state.lastVerificationTimestamp = block.timestamp;

uint64 lastVerifiedBlockId = local.b.lastVerifiedBlockId + local.numBlocksVerified;
local.slot = lastVerifiedBlockId % _config.blockRingBufferSize;

Expand Down
9 changes: 8 additions & 1 deletion packages/protocol/contracts/layer1/based/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ library TaikoData {
SlotA slotA; // slot 5
SlotB slotB; // slot 6
mapping(address account => uint256 bond) bondBalance;
uint256[43] __gap;

// Surge: Record the timestamp at which the last block verification happened to enforce
// stage-2 rollup requirement of blocking all owner operations if no block verified
// in the last 2 hours
uint256 lastVerificationTimestamp; // Slot 7

// Surge: Gap reduced by 1
uint256[42] __gap;
}
}
6 changes: 6 additions & 0 deletions packages/protocol/contracts/layer1/based/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents {
state.slotB.lastUnpausedAt = uint64(block.timestamp);
}

/// @inheritdoc ITaikoL1
// Surge: Stage-2 requirement
function getLastVerificationTimestamp() external view returns(uint256) {
return state.lastVerificationTimestamp;
}

/// @inheritdoc ITaikoL1
// Surge: switch to `view` to allow for dynamic chainid
function getConfig() public view virtual returns (TaikoData.Config memory) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "../based/ITaikoL1.sol";
import "@openzeppelin/contracts/governance/TimelockController.sol";

/// @title SurgeTimelockController
/// @dev Staisfies stage-2 rollup requirements by blocking executions if a block
/// has not been verified in a while.
/// @custom:security-contact [email protected]
contract SurgeTimelockedController is TimelockController {
/// @notice Address of taiko's inbox contract
ITaikoL1 internal taikoL1;

error ALREADY_INITIALIZED();
error LIVENESS_DISRUPTED();

constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) TimelockController(minDelay, proposers, executors, admin) {}

function init(address _taikoL1) external {
if(address(taikoL1) != address(0)) {
revert ALREADY_INITIALIZED();
}
taikoL1 = ITaikoL1(_taikoL1);
}

function execute(
address target,
uint256 value,
bytes calldata payload,
bytes32 predecessor,
bytes32 salt
) public payable override onlyRoleOrOpenRole(EXECUTOR_ROLE) {
if(_isLivenessDisrupted()) {
revert LIVENESS_DISRUPTED();
}

super.execute(target, value, payload, predecessor, salt);
}

function executeBatch(
address[] calldata targets,
uint256[] calldata values,
bytes[] calldata payloads,
bytes32 predecessor,
bytes32 salt
) public payable override onlyRoleOrOpenRole(EXECUTOR_ROLE) {
if(_isLivenessDisrupted()) {
revert LIVENESS_DISRUPTED();
}

super.executeBatch(targets, values, payloads, predecessor, salt);
}

/// @dev Returns `true` if an L2 block has not been verified in the last 1 day
function _isLivenessDisrupted() internal view returns(bool) {
uint256 lastVerificationTimestamp = taikoL1.getLastVerificationTimestamp();
return (block.timestamp - lastVerificationTimestamp) > 1 days;
}
}
6 changes: 4 additions & 2 deletions packages/protocol/script/layer1/surge/DeploySurgeOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/governance/TimelockController.sol";
import "@risc0/contracts/groth16/RiscZeroGroth16Verifier.sol";
import { SP1Verifier as SuccinctVerifier } from "@sp1-contracts/src/v4.0.0-rc.3/SP1VerifierPlonk.sol";

Expand All @@ -21,6 +20,7 @@ import "src/shared/tokenvault/BridgedERC721.sol";
import "src/shared/tokenvault/ERC1155Vault.sol";
import "src/shared/tokenvault/ERC20Vault.sol";
import "src/shared/tokenvault/ERC721Vault.sol";
import "src/layer1/surge/SurgeTimelockController.sol";
import "src/layer1/automata-attestation/AutomataDcapV3Attestation.sol";
import "src/layer1/automata-attestation/lib/PEMCertChainLib.sol";
import "src/layer1/automata-attestation/utils/SigVerifyLib.sol";
Expand Down Expand Up @@ -72,7 +72,7 @@ contract DeploySurgeOnL1 is DeployCapability {

uint256 timelockPeriod = uint64(vm.envUint("TIMELOCK_PERIOD"));
address timelockController = address(
new TimelockController(timelockPeriod, proposers, executors, address(0))
new SurgeTimelockedController(timelockPeriod, proposers, executors, address(0))
);
address contractOwner = timelockController;

Expand Down Expand Up @@ -103,6 +103,8 @@ contract DeploySurgeOnL1 is DeployCapability {
);
addressNotNull(taikoL1Addr, "taikoL1Addr");

SurgeTimelockedController(payable(timelockController)).init(taikoL1Addr);

SignalService(signalServiceAddr).authorize(taikoL1Addr, true);

console2.log("------------------------------------------");
Expand Down

0 comments on commit 19af3fe

Please sign in to comment.