Skip to content

Commit

Permalink
feat(protocol): allow guardian prover to pause block proving & verifi…
Browse files Browse the repository at this point in the history
…cation (#17286)

Co-authored-by: dantaik <[email protected]>
Co-authored-by: d1onys1us <[email protected]>
  • Loading branch information
3 people authored May 22, 2024
1 parent ef3d7d5 commit b955e0e
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 65 deletions.
44 changes: 23 additions & 21 deletions packages/protocol/contract_layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,29 @@
| __gap | uint256[48] | 253 | 0 | 1536 | contracts/L2/DelegateOwner.sol:DelegateOwner |

## GuardianProver
| Name | Type | Slot | Offset | Bytes | Contract |
|----------------|------------------------------------------------|------|--------|-------|--------------------------------------------------------|
| _initialized | uint8 | 0 | 0 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _initializing | bool | 0 | 1 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[50] | 1 | 0 | 1600 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _owner | address | 51 | 0 | 20 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 52 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _pendingOwner | address | 101 | 0 | 20 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 102 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| addressManager | address | 151 | 0 | 20 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 152 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __reentry | uint8 | 201 | 0 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __paused | uint8 | 201 | 1 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| lastUnpausedAt | uint64 | 201 | 2 | 8 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 202 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| guardianIds | mapping(address => uint256) | 251 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _approvals | mapping(uint32 => mapping(bytes32 => uint256)) | 252 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| guardians | address[] | 253 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| version | uint32 | 254 | 0 | 4 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| minGuardians | uint32 | 254 | 4 | 4 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[46] | 255 | 0 | 1472 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| Name | Type | Slot | Offset | Bytes | Contract |
|-------------------------|-------------------------------------------------|------|--------|-------|--------------------------------------------------------|
| _initialized | uint8 | 0 | 0 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _initializing | bool | 0 | 1 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[50] | 1 | 0 | 1600 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _owner | address | 51 | 0 | 20 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 52 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| _pendingOwner | address | 101 | 0 | 20 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 102 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| addressManager | address | 151 | 0 | 20 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 152 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __reentry | uint8 | 201 | 0 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __paused | uint8 | 201 | 1 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| lastUnpausedAt | uint64 | 201 | 2 | 8 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[49] | 202 | 0 | 1568 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| guardianIds | mapping(address => uint256) | 251 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| approvals | mapping(uint256 => mapping(bytes32 => uint256)) | 252 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| guardians | address[] | 253 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| version | uint32 | 254 | 0 | 4 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| minGuardians | uint32 | 254 | 4 | 4 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| provingAutoPauseEnabled | bool | 254 | 8 | 1 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| latestProofHash | mapping(uint256 => mapping(uint256 => bytes32)) | 255 | 0 | 32 | contracts/L1/provers/GuardianProver.sol:GuardianProver |
| __gap | uint256[45] | 256 | 0 | 1440 | contracts/L1/provers/GuardianProver.sol:GuardianProver |

## TaikoToken
| Name | Type | Slot | Offset | Bytes | Contract |
Expand Down
4 changes: 4 additions & 0 deletions packages/protocol/contracts/L1/ITaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ interface ITaikoL1 {
/// @param _maxBlocksToVerify Max number of blocks to verify.
function verifyBlocks(uint64 _maxBlocksToVerify) external;

/// @notice Pause block proving.
/// @param _pause True if paused.
function pauseProving(bool _pause) external;

/// @notice Gets the configuration of the TaikoL1 contract.
/// @return Config struct containing configuration parameters.
function getConfig() external view returns (TaikoData.Config memory);
Expand Down
3 changes: 1 addition & 2 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents, TaikoErrors {
LibVerifying.verifyBlocks(state, getConfig(), this, _maxBlocksToVerify);
}

/// @notice Pause block proving.
/// @param _pause True if paused.
/// @inheritdoc ITaikoL1
function pauseProving(bool _pause) external {
_authorizePause(msg.sender, _pause);
LibProving.pauseProving(state, _pause);
Expand Down
114 changes: 86 additions & 28 deletions packages/protocol/contracts/L1/provers/GuardianProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract GuardianProver is IVerifier, EssentialContract {
mapping(address guardian => uint256 id) public guardianIds;

/// @notice Mapping to store the approvals for a given hash, for a given version
mapping(uint32 version => mapping(bytes32 hash => uint256 approvalBits)) internal _approvals;
mapping(uint256 version => mapping(bytes32 proofHash => uint256 approvalBits)) public approvals;

/// @notice The set of guardians
/// @dev Slot 3
Expand All @@ -33,7 +33,14 @@ contract GuardianProver is IVerifier, EssentialContract {
/// @notice The minimum number of guardians required to approve
uint32 public minGuardians;

uint256[46] private __gap;
/// @notice True to enable pausing taiko proving upon conflicting proofs
bool public provingAutoPauseEnabled;

/// @notice Mapping from blockId to its latest proof hash
/// @dev Slot 5
mapping(uint256 version => mapping(uint256 blockId => bytes32 hash)) public latestProofHash;

uint256[45] private __gap;

/// @notice Emitted when a guardian proof is approved.
/// @param addr The address of the guardian.
Expand All @@ -60,9 +67,28 @@ contract GuardianProver is IVerifier, EssentialContract {
/// @param minGuardiansReached If the proof was submitted
event Approved(uint256 indexed operationId, uint256 approvalBits, bool minGuardiansReached);

/// @notice Emitted when a guardian prover submit a different proof for the same block
/// @param blockId The block ID
/// @param guardian The guardian prover address
/// @param currentProofHash The existing proof hash
/// @param newProofHash The new and different proof hash
/// @param provingPaused True if TaikoL1's proving is paused.
event ConflictingProofs(
uint256 indexed blockId,
address indexed guardian,
bytes32 currentProofHash,
bytes32 newProofHash,
bool provingPaused
);

/// @notice Emitted when auto pausing is enabled.
/// @param enabled True if TaikoL1 proving auto-pause is enabled.
event ProvingAutoPauseEnabled(bool indexed enabled);

error GP_INVALID_GUARDIAN();
error GP_INVALID_GUARDIAN_SET();
error GP_INVALID_MIN_GUARDIANS();
error GP_INVALID_STATUS();
error GV_PERMISSION_DENIED();
error GV_ZERO_ADDRESS();

Expand All @@ -76,13 +102,14 @@ contract GuardianProver is IVerifier, EssentialContract {
/// @notice Set the set of guardians
/// @param _newGuardians The new set of guardians
/// @param _minGuardians The minimum required to sign
/// @param _clearData true to invalidate all existing data.
function setGuardians(
address[] memory _newGuardians,
uint8 _minGuardians
uint8 _minGuardians,
bool _clearData
)
external
onlyOwner
nonReentrant
{
// We need at most 255 guardians (so the approval bits fit in a uint256)
if (_newGuardians.length == 0 || _newGuardians.length > type(uint8).max) {
Expand Down Expand Up @@ -113,12 +140,21 @@ contract GuardianProver is IVerifier, EssentialContract {
}

// Bump the version so previous approvals get invalidated
++version;
if (_clearData) ++version;

minGuardians = _minGuardians;
emit GuardiansUpdated(version, _newGuardians);
}

/// @dev Enables or disables proving auto pause.
/// @param _enable true to enable, false to disable.
function enableProvingAutoPause(bool _enable) external onlyOwner {
if (provingAutoPauseEnabled == _enable) revert GP_INVALID_STATUS();
provingAutoPauseEnabled = _enable;

emit ProvingAutoPauseEnabled(_enable);
}

/// @notice Enables unlimited allowance for Taiko L1 contract.
/// param _enable true if unlimited allowance is approved, false to set the allowance to 0.
function enableTaikoTokenAllowance(bool _enable) external onlyOwner {
Expand Down Expand Up @@ -153,19 +189,52 @@ contract GuardianProver is IVerifier, EssentialContract {
nonReentrant
returns (bool approved_)
{
bytes32 hash = keccak256(abi.encode(_meta, _tran, _proof.data));
approved_ = _approve(_meta.id, hash);
bytes32 proofHash = keccak256(abi.encode(_meta, _tran, _proof.data));
uint256 _version = version;
bytes32 currProofHash = latestProofHash[_version][_meta.id];

if (currProofHash == 0) {
latestProofHash[_version][_meta.id] = proofHash;
currProofHash = proofHash;
}

bool conflicting = currProofHash != proofHash;
bool pauseProving = conflicting && provingAutoPauseEnabled
&& address(this) == resolve(LibStrings.B_CHAIN_WATCHDOG, true);

emit GuardianApproval(msg.sender, _meta.id, _tran.blockHash, approved_, _proof.data);
if (conflicting) {
latestProofHash[_version][_meta.id] = proofHash;
emit ConflictingProofs(_meta.id, msg.sender, currProofHash, proofHash, pauseProving);
}

if (pauseProving) {
ITaikoL1(resolve(LibStrings.B_TAIKO, false)).pauseProving(true);
} else {
approved_ = _approve(_meta.id, proofHash);
emit GuardianApproval(msg.sender, _meta.id, _tran.blockHash, approved_, _proof.data);

if (approved_) {
_deleteApproval(hash);
ITaikoL1(resolve(LibStrings.B_TAIKO, false)).proveBlock(
_meta.id, abi.encode(_meta, _tran, _proof)
);
if (approved_) {
delete approvals[_version][proofHash];
delete latestProofHash[_version][_meta.id];

ITaikoL1(resolve(LibStrings.B_TAIKO, false)).proveBlock(
_meta.id, abi.encode(_meta, _tran, _proof)
);
}
}
}

/// @notice Pauses chain proving and verification.
function pauseTaikoProving() external whenNotPaused {
if (guardianIds[msg.sender] == 0) revert GP_INVALID_GUARDIAN();

if (address(this) != resolve(LibStrings.B_CHAIN_WATCHDOG, true)) {
revert GV_PERMISSION_DENIED();
}

ITaikoL1(resolve(LibStrings.B_TAIKO, false)).pauseProving(true);
}

/// @inheritdoc IVerifier
function verifyProof(
Context calldata _ctx,
Expand All @@ -178,38 +247,27 @@ contract GuardianProver is IVerifier, EssentialContract {
if (_ctx.msgSender != address(this)) revert GV_PERMISSION_DENIED();
}

/// @notice Returns if the hash is approved
/// @param _hash The hash to check
/// @return true if the hash is approved
function isApproved(bytes32 _hash) public view returns (bool) {
return _isApproved(_approvals[version][_hash]);
}

/// @notice Returns the number of guardians
/// @return The number of guardians
function numGuardians() public view returns (uint256) {
return guardians.length;
}

function _approve(uint256 _blockId, bytes32 _hash) internal returns (bool approved_) {
function _approve(uint256 _blockId, bytes32 _proofHash) internal returns (bool approved_) {
uint256 id = guardianIds[msg.sender];
if (id == 0) revert GP_INVALID_GUARDIAN();

uint32 _version = version;
uint256 _version = version;

unchecked {
_approvals[_version][_hash] |= 1 << (id - 1);
approvals[_version][_proofHash] |= 1 << (id - 1);
}

uint256 _approval = _approvals[_version][_hash];
uint256 _approval = approvals[_version][_proofHash];
approved_ = _isApproved(_approval);
emit Approved(_blockId, _approval, approved_);
}

function _deleteApproval(bytes32 _hash) private {
delete _approvals[version][_hash];
}

function _isApproved(uint256 _approvalBits) private view returns (bool) {
uint256 count;
uint256 bits = _approvalBits;
Expand Down
6 changes: 5 additions & 1 deletion packages/protocol/deployments/mainnet-contract-logs-L1.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@
- deployed on May 1, 2024 @commit `56dddf2b6`
- admin.taiko.eth accepted the ownership @tx`0x0ed114fee6de4e3e2206cea44e6632ec0c4588f73648d98d8df5dc0183b07885`
- Upgraded from `0x717DC5E3814591790BcB1fD9259eEdA7c14ce9CF` to `0x750221E951b77a2Cb4046De41Ec5F6d1aa7942D2` @commit `b90b932` @tx`0x416560cd96dc75ccffebe889e8d1ab3e08b33f814dc4a2bf7c6f9555071d1f6f`
- Upgraded from `0x750221E951b77a2Cb4046De41Ec5F6d1aa7942D2` to `0x253E47F2b1e91F2001d3578aeB24C0ccF464b65es` @commit `cd5144255` @tx`0x8030569e293baddbc4e8b26688a1ecf14a231d86c90e9d02dad1e919ea2f3964`
- Upgraded from `0x750221E951b77a2Cb4046De41Ec5F6d1aa7942D2` to `0x253E47F2b1e91F2001d3578aeB24C0ccF464b65es` @commit `cd5144255` @tx`0x8030569e293baddbc4e8b26688a1ecf14a231d86c90e9d02dad1e919ea2f3964
- todo:
- upgrade impl again after proving-pausing PR merged

#### guardian_prover

Expand All @@ -232,6 +234,8 @@
- deployed on May 1, 2024 @commit `56dddf2b6`
- Upgraded from `0x717DC5E3814591790BcB1fD9259eEdA7c14ce9CF` to `0x750221E951b77a2Cb4046De41Ec5F6d1aa7942D2` @commit `b90b932` @tx`0x416560cd96dc75ccffebe889e8d1ab3e08b33f814dc4a2bf7c6f9555071d1f6f`
- Upgraded from `0x750221E951b77a2Cb4046De41Ec5F6d1aa7942D2` to `0x253E47F2b1e91F2001d3578aeB24C0ccF464b65e` @commit `cd5144255` @tx`0x8030569e293baddbc4e8b26688a1ecf14a231d86c90e9d02dad1e919ea2f3964`
- todo:
- upgrade impl again after proving-pausing PR merged

#### p256_verifier

Expand Down
6 changes: 4 additions & 2 deletions packages/protocol/script/DeployOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,13 @@ contract DeployOnL1 is DeployCapability {
address[] memory guardians = vm.envAddress("GUARDIAN_PROVERS", ",");

GuardianProver(guardianProverMinority).setGuardians(
guardians, uint8(NUM_MIN_MINORITY_GUARDIANS)
guardians, uint8(NUM_MIN_MINORITY_GUARDIANS), true
);
GuardianProver(guardianProverMinority).transferOwnership(owner);

GuardianProver(guardianProver).setGuardians(guardians, uint8(NUM_MIN_MAJORITY_GUARDIANS));
GuardianProver(guardianProver).setGuardians(
guardians, uint8(NUM_MIN_MAJORITY_GUARDIANS), true
);
GuardianProver(guardianProver).transferOwnership(owner);

// No need to proxy these, because they are 3rd party. If we want to modify, we simply
Expand Down
Loading

0 comments on commit b955e0e

Please sign in to comment.