Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol): allow guardian prover to pause block proving & verification #17286

Merged
merged 30 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6410aa7
merge Guardians.sol into GuardianProver.sol
dantaik May 21, 2024
25ef626
Update GuardianProver.t.sol
dantaik May 21, 2024
d5ac6e4
forge fmt & update contract layout table
dantaik May 21, 2024
6eb9538
Update GuardianProver.sol
dantaik May 21, 2024
a26d4d9
rename
dantaik May 21, 2024
b69ee3f
Merge branch 'guardian_prover' into guardian_prover_pause_proving
dantaik May 21, 2024
8b6c94e
forge fmt & update contract layout table
dantaik May 21, 2024
a1ae402
Update GuardianProver.sol
dantaik May 21, 2024
3656ec7
more
dantaik May 21, 2024
7332576
Update GuardianProver.sol
dantaik May 21, 2024
0ac558d
Update GuardianProver.sol
dantaik May 21, 2024
643e420
fix
dantaik May 21, 2024
4de0558
forge fmt & update contract layout table
dantaik May 21, 2024
edb7aab
Update GuardianProver.sol
dantaik May 21, 2024
b56845f
forge fmt & update contract layout table
dantaik May 21, 2024
98cfe96
Update mainnet-contract-logs.md
dantaik May 21, 2024
b894565
isApproved
dantaik May 21, 2024
72c5470
Merge branch 'main' into guardian_prover_pause_proving
dantaik May 21, 2024
2a857e2
forge fmt & update contract layout table
dantaik May 21, 2024
cf6bf6e
Merge branch 'main' into guardian_prover_pause_proving
dionysuzx May 21, 2024
aea16aa
Merge branch 'main' into guardian_prover_pause_proving
dantaik May 21, 2024
44eb1c3
Empty-Commit
dantaik May 21, 2024
617e07c
Merge branch 'main' into guardian_prover_pause_proving
dantaik May 21, 2024
f3f02aa
Update mainnet-contract-logs-L1.md
dantaik May 21, 2024
f7ab523
feat(protocol): allow guardian to pause chain proving knowingly (#17293)
dantaik May 21, 2024
82ee910
Update GuardianProver.sol
dantaik May 22, 2024
39bccca
Update GuardianProver.sol
dantaik May 22, 2024
2d14237
Update mainnet-contract-logs-L1.md
dantaik May 22, 2024
5156fab
allow keep existing data in guardian provers
dantaik May 22, 2024
742c53d
Update GuardianProver.sol
dantaik May 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
116 changes: 83 additions & 33 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,14 +102,7 @@ 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
function setGuardians(
address[] memory _newGuardians,
uint8 _minGuardians
)
external
onlyOwner
nonReentrant
{
function setGuardians(address[] memory _newGuardians, uint8 _minGuardians) external onlyOwner {
// 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();
Expand Down Expand Up @@ -138,6 +157,15 @@ contract GuardianProver is IVerifier, EssentialContract {
tko.safeTransfer(_to, amount);
}

/// @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);
}

/// @dev Called by guardians to approve a guardian proof
/// @param _meta The block's metadata.
/// @param _tran The valid transition.
Expand All @@ -153,17 +181,50 @@ 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;
}

emit GuardianApproval(msg.sender, _meta.id, _tran.blockHash, approved_, _proof.data);
bool conflicting = currProofHash != proofHash;
bool pauseProving = conflicting && provingAutoPauseEnabled
&& address(this) == resolve(LibStrings.B_CHAIN_WATCHDOG, true);

if (approved_) {
_deleteApproval(hash);
ITaikoL1(resolve(LibStrings.B_TAIKO, false)).proveBlock(
_meta.id, abi.encode(_meta, _tran, _proof)
);
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);
Brechtpd marked this conversation as resolved.
Show resolved Hide resolved
} else {
approved_ = _approve(_meta.id, proofHash);
emit GuardianApproval(msg.sender, _meta.id, _tran.blockHash, approved_, _proof.data);

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
Expand All @@ -178,38 +239,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 and tested in Hekla.

#### 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 and tested in Hekla.

#### p256_verifier

Expand Down
3 changes: 0 additions & 3 deletions packages/protocol/test/L1/GuardianProver1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ contract TestGuardianProver1 is TaikoTest {
for (uint256 i; i < 6; ++i) {
vm.prank(signers[0]);
assertEq(target.approve(hash), false);
assertEq(target.isApproved(hash), false);
}

hash = keccak256("singapore");
Expand All @@ -75,13 +74,11 @@ contract TestGuardianProver1 is TaikoTest {
target.approve(hash);

assertEq(target.approve(hash), i >= 3);
assertEq(target.isApproved(hash), i >= 3);
vm.stopPrank();
}

// changing the settings will invalid all approval history
target.setGuardians(signers, 3);
assertEq(target.version(), 2);
assertEq(target.isApproved(hash), false);
}
}