Skip to content

Commit c3c62d9

Browse files
committed
feat: add pauser to update funcs
1 parent f6a60f4 commit c3c62d9

File tree

6 files changed

+76
-5
lines changed

6 files changed

+76
-5
lines changed

docs/multichain/destination/OperatorTableUpdater.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Confirms a new global table root by verifying a BN254 certificate signed by the
6969
* Emits a `NewGlobalTableRoot` event
7070

7171
*Requirements*:
72+
* The contract MUST NOT be paused for global root updates
7273
* The `referenceTimestamp` MUST NOT be in the future
7374
* The `referenceTimestamp` MUST be greater than `_latestReferenceTimestamp`
7475
* The certificate's `messageHash` MUST match the expected EIP-712 hash
@@ -110,6 +111,7 @@ Updates an operator table by verifying its inclusion in a confirmed global table
110111
* Calls `ecdsaCertificateVerifier.updateOperatorTable` with the decoded operator info
111112

112113
*Requirements*:
114+
* The contract MUST NOT be paused for operator table updates
113115
* The `globalTableRoot` MUST be valid (not disabled)
114116
* The `referenceTimestamp` MUST be greater than the latest timestamp for the operator set
115117
* The merkle proof MUST verify the operator table's inclusion in the global root
@@ -181,7 +183,7 @@ function disableRoot(
181183
) external;
182184
```
183185

184-
Disables a global table root, preventing further operator table updates against it. This function also prevents the `CertificateVerifier` from verifying certificates. The function is intended to prevent a malicious or invalid root from being used by downstream consumers.
186+
Disables a global table root, preventing further operator table updates against it. This function also prevents the `CertificateVerifier` from verifying certificates. The function is intended to prevent a malicious or invalid root from being used by downstream consumers. Once a root is disabled, it cannot be re-enabled.
185187

186188
*Effects*:
187189
* Sets `_isRootValid[globalTableRoot]` to `false`
@@ -217,4 +219,4 @@ Updates the operator table for the `generator` itself. This operatorSet is a ["s
217219

218220
*Requirements*:
219221
* Caller MUST be the `owner`
220-
* Meet all requirements in [`bn254CertificateVerifier.updateOperatorTable`](../destination/CertificateVerifier.md#updateoperatortable-1)
222+
* Meet all requirements in [`bn254CertificateVerifier.updateOperatorTable`](../destination/CertificateVerifier.md#updateoperatortable-1)

pkg/bindings/OperatorTableUpdater/binding.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/contracts/multichain/OperatorTableUpdater.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ contract OperatorTableUpdater is
8888
bytes32 globalTableRoot,
8989
uint32 referenceTimestamp,
9090
uint32 referenceBlockNumber
91-
) external {
91+
) external onlyWhenNotPaused(PAUSED_GLOBAL_ROOT_UPDATE) {
9292
// Table roots can only be updated for current or past timestamps and after the latest reference timestamp
9393
require(referenceTimestamp <= block.timestamp, GlobalTableRootInFuture());
9494
require(referenceTimestamp > _latestReferenceTimestamp, GlobalTableRootStale());
@@ -124,7 +124,7 @@ contract OperatorTableUpdater is
124124
uint32 operatorSetIndex,
125125
bytes calldata proof,
126126
bytes calldata operatorTableBytes
127-
) external {
127+
) external onlyWhenNotPaused(PAUSED_OPERATOR_TABLE_UPDATE) {
128128
(
129129
OperatorSet memory operatorSet,
130130
CurveType curveType,

src/contracts/multichain/OperatorTableUpdaterStorage.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import "../interfaces/IECDSACertificateVerifier.sol";
88
abstract contract OperatorTableUpdaterStorage is IOperatorTableUpdater {
99
// Constants
1010

11+
/// @notice Index for flag that pauses calling `updateGlobalTableRoot`
12+
uint8 internal constant PAUSED_GLOBAL_ROOT_UPDATE = 0;
13+
14+
/// @notice Index for flag that pauses calling `updateOperatorTable`
15+
uint8 internal constant PAUSED_OPERATOR_TABLE_UPDATE = 1;
16+
1117
bytes32 public constant GLOBAL_TABLE_ROOT_CERT_TYPEHASH =
1218
keccak256("GlobalTableRootCert(bytes32 globalTableRoot,uint32 referenceTimestamp,uint32 referenceBlockNumber)");
1319

src/test/tree/OperatorTableUpdaterUnit.tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
│ └── given that the contract is not initialized
77
│ └── it should set the owner, generator, threshold, and update operator table & emit events
88
├── when confirmGlobalTableRoot is called
9+
│ ├── given that the contract is paused for global root updates
10+
│ │ └── it should revert with CurrentlyPaused
911
│ ├── given that the reference timestamp is in the future
1012
│ │ └── it should revert with GlobalTableRootInFuture
1113
│ ├── given that the reference timestamp is not greater than latest
@@ -17,6 +19,8 @@
1719
│ └── given that all parameters are valid
1820
│ └── it should update global table root, reference timestamp, block number mappings (both directions) & emit NewGlobalTableRoot event
1921
├── when updateOperatorTable is called
22+
│ ├── given that the contract is paused for operator table updates
23+
│ │ └── it should revert with CurrentlyPaused
2024
│ ├── given that the reference timestamp is not greater than operator set's latest
2125
│ │ └── it should revert with TableUpdateForPastTimestamp
2226
│ ├── given that the global table root is not valid

src/test/unit/OperatorTableUpdaterUnit.t.sol

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,23 @@ contract OperatorTableUpdaterUnitTests_confirmGlobalTableRoot is OperatorTableUp
217217
operatorTableUpdater.confirmGlobalTableRoot(mockCertificate, bytes32(0), referenceTimestamp + 1, referenceBlockNumber);
218218
}
219219

220+
function testFuzz_revert_paused(Randomness r) public rand(r) {
221+
// Pause the confirmGlobalTableRoot functionality (bit index 0)
222+
uint pausedStatus = 1 << 0; // Set bit 0 to pause PAUSED_GLOBAL_ROOT_UPDATE
223+
cheats.prank(pauser);
224+
operatorTableUpdater.pause(pausedStatus);
225+
226+
uint32 referenceTimestamp = r.Uint32(operatorTableUpdater.getLatestReferenceTimestamp() + 1, type(uint32).max);
227+
uint32 referenceBlockNumber = r.Uint32();
228+
bytes32 globalTableRoot = bytes32(r.Uint256(1, type(uint).max));
229+
mockCertificate.messageHash =
230+
operatorTableUpdater.getGlobalTableUpdateMessageHash(globalTableRoot, referenceTimestamp, referenceBlockNumber);
231+
232+
// Try to confirm a global table root while paused
233+
cheats.expectRevert(IPausable.CurrentlyPaused.selector);
234+
operatorTableUpdater.confirmGlobalTableRoot(mockCertificate, globalTableRoot, referenceTimestamp, referenceBlockNumber);
235+
}
236+
220237
function testFuzz_revert_staleCertificate(Randomness r) public rand(r) {
221238
uint32 referenceBlockNumber = uint32(block.number);
222239
mockCertificate.messageHash =
@@ -276,6 +293,27 @@ contract OperatorTableUpdaterUnitTests_updateOperatorTable_BN254 is OperatorTabl
276293
bn254CertificateVerifierMock.setLatestReferenceTimestamp(operatorSet, referenceTimestamp);
277294
}
278295

296+
function testFuzz_BN254_revert_paused(Randomness r) public rand(r) {
297+
// Pause the updateOperatorTable functionality (bit index 1)
298+
uint pausedStatus = 1 << 1; // Set bit 1 to pause PAUSED_OPERATOR_TABLE_UPDATE
299+
cheats.prank(pauser);
300+
operatorTableUpdater.pause(pausedStatus);
301+
302+
// Generate random operatorSetInfo and operatorSetConfig
303+
BN254OperatorSetInfo memory operatorSetInfo = _generateRandomBN254OperatorSetInfo(r);
304+
bytes memory operatorSetInfoBytes = abi.encode(operatorSetInfo);
305+
OperatorSetConfig memory operatorSetConfig = _generateRandomOperatorSetConfig(r);
306+
bytes memory operatorTable = abi.encode(defaultOperatorSet, CurveType.BN254, operatorSetConfig, operatorSetInfoBytes);
307+
308+
// First create a valid root
309+
bytes32 globalTableRoot = bytes32(r.Uint256(1, type(uint).max));
310+
_updateGlobalTableRoot(globalTableRoot);
311+
312+
// Try to update operator table while paused
313+
cheats.expectRevert(IPausable.CurrentlyPaused.selector);
314+
operatorTableUpdater.updateOperatorTable(uint32(block.timestamp), globalTableRoot, 0, new bytes(0), operatorTable);
315+
}
316+
279317
function testFuzz_BN254_revert_staleTableUpdate(Randomness r) public rand(r) {
280318
uint32 referenceTimestamp = r.Uint32(uint32(block.timestamp), type(uint32).max);
281319
_setLatestReferenceTimestampBN254(defaultOperatorSet, referenceTimestamp);
@@ -397,6 +435,27 @@ contract OperatorTableUpdaterUnitTests_updateOperatorTable_ECDSA is OperatorTabl
397435
ecdsaCertificateVerifierMock.setLatestReferenceTimestamp(operatorSet, referenceTimestamp);
398436
}
399437

438+
function testFuzz_ECDSA_revert_paused(Randomness r) public rand(r) {
439+
// Pause the updateOperatorTable functionality (bit index 1)
440+
uint pausedStatus = 1 << 1; // Set bit 1 to pause PAUSED_OPERATOR_TABLE_UPDATE
441+
cheats.prank(pauser);
442+
operatorTableUpdater.pause(pausedStatus);
443+
444+
// Generate random operatorInfos and operatorSetConfig
445+
ECDSAOperatorInfo[] memory operatorInfos = _generateRandomECDSAOperatorInfos(r);
446+
bytes memory operatorInfosBytes = abi.encode(operatorInfos);
447+
OperatorSetConfig memory operatorSetConfig = _generateRandomOperatorSetConfig(r);
448+
bytes memory operatorTable = abi.encode(defaultOperatorSet, CurveType.ECDSA, operatorSetConfig, operatorInfosBytes);
449+
450+
// First create a valid root
451+
bytes32 globalTableRoot = bytes32(r.Uint256(1, type(uint).max));
452+
_updateGlobalTableRoot(globalTableRoot);
453+
454+
// Try to update operator table while paused
455+
cheats.expectRevert(IPausable.CurrentlyPaused.selector);
456+
operatorTableUpdater.updateOperatorTable(uint32(block.timestamp), globalTableRoot, 0, new bytes(0), operatorTable);
457+
}
458+
400459
function testFuzz_ECDSA_revert_rootDisabled(Randomness r) public rand(r) {
401460
// Generate random operatorSetInfo and operatorSetConfig
402461
ECDSAOperatorInfo[] memory emptyOperatorSetInfo;

0 commit comments

Comments
 (0)