forked from taikoxyz/taiko-mono
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(protocol): merge Guardians.sol into GuardianProver.sol (taik…
…oxyz#17285) Co-authored-by: dantaik <[email protected]>
- Loading branch information
Showing
5 changed files
with
150 additions
and
165 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,23 +3,37 @@ pragma solidity 0.8.24; | |
|
||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
|
||
import "../../common/EssentialContract.sol"; | ||
import "../../common/LibStrings.sol"; | ||
import "../../verifiers/IVerifier.sol"; | ||
import "../tiers/ITierProvider.sol"; | ||
import "../ITaikoL1.sol"; | ||
import "./Guardians.sol"; | ||
|
||
/// @title GuardianProver | ||
/// This prover uses itself as the verifier. | ||
/// @custom:security-contact [email protected] | ||
contract GuardianProver is IVerifier, Guardians { | ||
contract GuardianProver is IVerifier, EssentialContract { | ||
using SafeERC20 for IERC20; | ||
|
||
error GV_PERMISSION_DENIED(); | ||
error GV_ZERO_ADDRESS(); | ||
/// @notice Contains the index of the guardian in `guardians` plus one (zero means not a | ||
/// guardian) | ||
/// @dev Slot 1 | ||
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; | ||
|
||
/// @notice The set of guardians | ||
/// @dev Slot 3 | ||
address[] public guardians; | ||
|
||
/// @notice The version of the guardians | ||
/// @dev Slot 4 | ||
uint32 public version; | ||
|
||
uint256[50] private __gap; | ||
/// @notice The minimum number of guardians required to approve | ||
uint32 public minGuardians; | ||
|
||
uint256[46] private __gap; | ||
|
||
/// @notice Emitted when a guardian proof is approved. | ||
/// @param addr The address of the guardian. | ||
|
@@ -35,13 +49,76 @@ contract GuardianProver is IVerifier, Guardians { | |
bytes proofData | ||
); | ||
|
||
/// @notice Emitted when the set of guardians is updated | ||
/// @param version The new version | ||
/// @param guardians The new set of guardians | ||
event GuardiansUpdated(uint32 version, address[] guardians); | ||
|
||
/// @notice Emitted when an approval is made | ||
/// @param operationId The operation ID | ||
/// @param approvalBits The new approval bits | ||
/// @param minGuardiansReached If the proof was submitted | ||
event Approved(uint256 indexed operationId, uint256 approvalBits, bool minGuardiansReached); | ||
|
||
error GP_INVALID_GUARDIAN(); | ||
error GP_INVALID_GUARDIAN_SET(); | ||
error GP_INVALID_MIN_GUARDIANS(); | ||
error GV_PERMISSION_DENIED(); | ||
error GV_ZERO_ADDRESS(); | ||
|
||
/// @notice Initializes the contract. | ||
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero. | ||
/// @param _addressManager The address of the {AddressManager} contract. | ||
function init(address _owner, address _addressManager) external initializer { | ||
__Essential_init(_owner, _addressManager); | ||
} | ||
|
||
/// @notice Set the set of guardians | ||
/// @param _newGuardians The new set of guardians | ||
/// @param _minGuardians The minimum required to sign | ||
function setGuardians( | ||
address[] memory _newGuardians, | ||
uint8 _minGuardians | ||
) | ||
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) { | ||
revert GP_INVALID_GUARDIAN_SET(); | ||
} | ||
// Minimum number of guardians to approve is at least equal or greater than half the | ||
// guardians (rounded up) and less or equal than the total number of guardians | ||
if (_minGuardians == 0 || _minGuardians > _newGuardians.length) { | ||
revert GP_INVALID_MIN_GUARDIANS(); | ||
} | ||
|
||
// Delete the current guardians | ||
for (uint256 i; i < guardians.length; ++i) { | ||
delete guardianIds[guardians[i]]; | ||
} | ||
delete guardians; | ||
|
||
// Set the new guardians | ||
for (uint256 i; i < _newGuardians.length; ++i) { | ||
address guardian = _newGuardians[i]; | ||
if (guardian == address(0)) revert GP_INVALID_GUARDIAN(); | ||
// This makes sure there are not duplicate addresses | ||
if (guardianIds[guardian] != 0) revert GP_INVALID_GUARDIAN_SET(); | ||
|
||
// Save and index the guardian | ||
guardians.push(guardian); | ||
guardianIds[guardian] = guardians.length; | ||
} | ||
|
||
// Bump the version so previous approvals get invalidated | ||
++version; | ||
|
||
minGuardians = _minGuardians; | ||
emit GuardiansUpdated(version, _newGuardians); | ||
} | ||
|
||
/// @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 { | ||
|
@@ -77,12 +154,12 @@ contract GuardianProver is IVerifier, Guardians { | |
returns (bool approved_) | ||
{ | ||
bytes32 hash = keccak256(abi.encode(_meta, _tran, _proof.data)); | ||
approved_ = approve(_meta.id, hash); | ||
approved_ = _approve(_meta.id, hash); | ||
|
||
emit GuardianApproval(msg.sender, _meta.id, _tran.blockHash, approved_, _proof.data); | ||
|
||
if (approved_) { | ||
deleteApproval(hash); | ||
_deleteApproval(hash); | ||
ITaikoL1(resolve(LibStrings.B_TAIKO, false)).proveBlock( | ||
_meta.id, abi.encode(_meta, _tran, _proof) | ||
); | ||
|
@@ -100,4 +177,50 @@ contract GuardianProver is IVerifier, Guardians { | |
{ | ||
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_) { | ||
uint256 id = guardianIds[msg.sender]; | ||
if (id == 0) revert GP_INVALID_GUARDIAN(); | ||
|
||
uint32 _version = version; | ||
|
||
unchecked { | ||
_approvals[_version][_hash] |= 1 << (id - 1); | ||
} | ||
|
||
uint256 _approval = _approvals[_version][_hash]; | ||
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; | ||
uint256 guardiansLength = guardians.length; | ||
unchecked { | ||
for (uint256 i; i < guardiansLength; ++i) { | ||
if (bits & 1 == 1) ++count; | ||
if (count == minGuardians) return true; | ||
bits >>= 1; | ||
} | ||
} | ||
return false; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.