Skip to content

Commit

Permalink
feat: alert per rollup chain ID
Browse files Browse the repository at this point in the history
  • Loading branch information
neutiyoo committed May 16, 2024
1 parent 0d8fdec commit d64fa64
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 43 deletions.
37 changes: 25 additions & 12 deletions contracts/src/core/MachServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {
ZeroAddress,
AlreadyInAllowlist,
NotInAllowlist,
NoStatusChange,
InvalidRollupChainID,
InvalidReferenceBlockNum,
InsufficientThreshold,
InvalidStartIndex,
Expand Down Expand Up @@ -177,10 +179,10 @@ contract MachServiceManager is
* @notice Remove an Alert.
* @param messageHash The message hash of the alert
*/
function removeAlert(bytes32 messageHash) external onlyOwner {
bool ret = _messageHashes.remove(messageHash);
function removeAlert(uint256 rollupChainId, bytes32 messageHash) external onlyOwner {
bool ret = _messageHashes[rollupChainId].remove(messageHash);
if (ret) {
_resolvedMessageHashes.add(messageHash);
_resolvedMessageHashes[rollupChainId].add(messageHash);
emit AlertRemoved(messageHash, _msgSender());
}
}
Expand Down Expand Up @@ -252,6 +254,7 @@ contract MachServiceManager is
* - and check whether quorum has been achieved or not.
*/
function confirmAlert(
uint256 rollupChainId,
AlertHeader calldata alertHeader,
NonSignerStakesAndSignature memory nonSignerStakesAndSignature
) external whenNotPaused onlyAlertConfirmer {
Expand All @@ -261,7 +264,7 @@ contract MachServiceManager is
}

// check is it is the resolved alert before
if (_resolvedMessageHashes.contains(alertHeader.messageHash)) {
if (_resolvedMessageHashes[rollupChainId].contains(alertHeader.messageHash)) {
revert ResolvedAlert();
}

Expand Down Expand Up @@ -305,7 +308,7 @@ contract MachServiceManager is
}

// store alert
bool success = _messageHashes.add(alertHeader.messageHash);
bool success = _messageHashes[rollupChainId].add(alertHeader.messageHash);
if (!success) {
revert AlreadyAdded();
}
Expand All @@ -318,18 +321,22 @@ contract MachServiceManager is
//////////////////////////////////////////////////////////////////////////////

/// @notice Returns the length of total alerts
function totalAlerts() external view returns (uint256) {
return _messageHashes.length();
function totalAlerts(uint256 rollupChainId) external view returns (uint256) {
return _messageHashes[rollupChainId].length();
}

/// @notice Checks if messageHash exists
function contains(bytes32 messageHash) external view returns (bool) {
return _messageHashes.contains(messageHash);
function contains(uint256 rollupChainId, bytes32 messageHash) external view returns (bool) {
return _messageHashes[rollupChainId].contains(messageHash);
}

/// @notice Returns an array of messageHash
function queryMessageHashes(uint256 start, uint256 querySize) external view returns (bytes32[] memory) {
uint256 length = _messageHashes.length();
function queryMessageHashes(uint256 rollupChainId, uint256 start, uint256 querySize)
external
view
returns (bytes32[] memory)
{
uint256 length = _messageHashes[rollupChainId].length();

if (start >= length) {
revert InvalidStartIndex();
Expand All @@ -343,7 +350,7 @@ contract MachServiceManager is

bytes32[] memory output = new bytes32[](end - start);
for (uint256 i = start; i < end; ++i) {
output[i - start] = _messageHashes.at(i);
output[i - start] = _messageHashes[rollupChainId].at(i);
}

return output;
Expand Down Expand Up @@ -388,6 +395,12 @@ contract MachServiceManager is
}

function _setRollupChainID(uint256 rollupChainId, bool status) internal {
if (rollupChainId < 1) {
revert InvalidRollupChainID();
}
if (rollupChainIDs[rollupChainId] == status) {
revert NoStatusChange();
}
rollupChainIDs[rollupChainId] = status;
emit RollupChainIDUpdated(rollupChainId, status);
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/src/core/MachServiceManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract contract MachServiceManagerStorage {
uint256 public constant THRESHOLD_DENOMINATOR = 100;

// Slot 0
EnumerableSet.Bytes32Set internal _messageHashes;
mapping(uint256 => EnumerableSet.Bytes32Set) internal _messageHashes;

// Slot 1
/// @notice Ethereum addresses of currently register operators
Expand All @@ -37,7 +37,7 @@ abstract contract MachServiceManagerStorage {

// slot 4
/// @notice Resolved message hashes, prevent aggregator from replay any resolved alert
EnumerableSet.Bytes32Set internal _resolvedMessageHashes;
mapping(uint256 => EnumerableSet.Bytes32Set) internal _resolvedMessageHashes;

// slot 5
/// @notice Role for whitelisting operators
Expand Down
2 changes: 2 additions & 0 deletions contracts/src/error/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ error InvalidStartIndex();
error InvalidConfirmer();
error NotWhitelister();
error InvalidSender();
error NoStatusChange();
error InvalidRollupChainID();
error InvalidReferenceBlockNum();
error InsufficientThreshold();
error InsufficientThresholdPercentages();
Expand Down
12 changes: 8 additions & 4 deletions contracts/src/interfaces/IMachServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ interface IMachServiceManager is IServiceManager {
* @notice Remove an Alert.
* @param messageHash The message hash of the alert
*/
function removeAlert(bytes32 messageHash) external;
function removeAlert(uint256 rollupChainId, bytes32 messageHash) external;

/**
* @notice Update quorum threshold percentage
Expand All @@ -138,16 +138,20 @@ interface IMachServiceManager is IServiceManager {
* - and check whether quorum has been achieved or not.
*/
function confirmAlert(
uint256 rollupChainId,
AlertHeader calldata alertHeader,
BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature
) external;

/// @notice Returns the length of total alerts
function totalAlerts() external view returns (uint256);
function totalAlerts(uint256 rollupChainId) external view returns (uint256);

/// @notice Checks if messageHash exists
function contains(bytes32 messageHash) external view returns (bool);
function contains(uint256 rollupChainId, bytes32 messageHash) external view returns (bool);

/// @notice Returns an array of messageHash
function queryMessageHashes(uint256 start, uint256 querySize) external view returns (bytes32[] memory);
function queryMessageHashes(uint256 rollupChainId, uint256 start, uint256 querySize)
external
view
returns (bytes32[] memory);
}
74 changes: 49 additions & 25 deletions contracts/test/MachServiceManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ contract MachServiceManagerTest is BLSAVSDeployer {
_setAggregatePublicKeysAndSignature();
}

function test_Init_RevertIfImpleBeingInitialized() public {
uint256[] memory ids = new uint256[](0);
vm.expectRevert("Initializable: contract is already initialized");
serviceManagerImplementation.initialize(
pauserRegistry, 0, proxyAdminOwner, proxyAdminOwner, proxyAdminOwner, ids
);
}

function test_SetConfirmer() public {
address newConfirmer = address(42);
vm.startPrank(proxyAdminOwner);
Expand Down Expand Up @@ -223,6 +231,22 @@ contract MachServiceManagerTest is BLSAVSDeployer {
serviceManager.setRollupChainID(42, true);
}

function test_SetRollupChainID_RevertIfInvalidRollupChainID() public {
vm.startPrank(proxyAdminOwner);

vm.expectRevert(InvalidRollupChainID.selector);
serviceManager.setRollupChainID(0, true);
vm.stopPrank();
}

function test_SetRollupChainID_RevertIfNoStatusChange() public {
vm.startPrank(proxyAdminOwner);

vm.expectRevert(NoStatusChange.selector);
serviceManager.setRollupChainID(1, true);
vm.stopPrank();
}

function test_confirmAlert() public {
vm.startPrank(proxyAdminOwner);
serviceManager.disableAllowlist();
Expand All @@ -245,14 +269,14 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(proxyAdminOwner);
vm.expectEmit();
assertEq(serviceManager.totalAlerts(), 0);
assertFalse(serviceManager.contains("foo"));
assertEq(serviceManager.totalAlerts(1), 0);
assertFalse(serviceManager.contains(1, "foo"));

emit AlertConfirmed(msgHash, alertHeader.messageHash);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);

assertEq(serviceManager.totalAlerts(), 1);
assertTrue(serviceManager.contains("foo"));
assertEq(serviceManager.totalAlerts(1), 1);
assertTrue(serviceManager.contains(1, "foo"));

vm.stopPrank();
}
Expand All @@ -277,7 +301,7 @@ contract MachServiceManagerTest is BLSAVSDeployer {
referenceBlockNumber: referenceBlockNumber
});
vm.expectRevert(InvalidConfirmer.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
}

function test_confirmAlert_RevertIfInvalidSender() public {
Expand Down Expand Up @@ -306,7 +330,7 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(address(this));
vm.expectRevert(InvalidSender.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -331,9 +355,9 @@ contract MachServiceManagerTest is BLSAVSDeployer {
});

vm.startPrank(proxyAdminOwner);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.expectRevert(AlreadyAdded.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -359,7 +383,7 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(proxyAdminOwner);
vm.expectRevert(InvalidQuorumParam.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -384,11 +408,11 @@ contract MachServiceManagerTest is BLSAVSDeployer {
});

vm.startPrank(proxyAdminOwner);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.removeAlert("foo");
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
serviceManager.removeAlert(1, "foo");

vm.expectRevert(ResolvedAlert.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -414,7 +438,7 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(proxyAdminOwner);
vm.expectRevert(InvalidReferenceBlockNum.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -440,7 +464,7 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(proxyAdminOwner);
vm.expectRevert(InvalidQuorumThresholdPercentage.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -466,7 +490,7 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(proxyAdminOwner);
vm.expectRevert(InsufficientThresholdPercentages.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

Expand All @@ -492,41 +516,41 @@ contract MachServiceManagerTest is BLSAVSDeployer {

vm.startPrank(proxyAdminOwner);
vm.expectRevert(InsufficientThreshold.selector);
serviceManager.confirmAlert(alertHeader, nonSignerStakesAndSignature);
serviceManager.confirmAlert(1, alertHeader, nonSignerStakesAndSignature);
vm.stopPrank();
}

function test_removeAlert() public {
test_confirmAlert();
vm.startPrank(proxyAdminOwner);
assertEq(serviceManager.totalAlerts(), 1);
assertTrue(serviceManager.contains("foo"));
assertEq(serviceManager.totalAlerts(1), 1);
assertTrue(serviceManager.contains(1, "foo"));

vm.expectEmit();
emit AlertRemoved("foo", msg.sender);
serviceManager.removeAlert("foo");
serviceManager.removeAlert(1, "foo");

assertFalse(serviceManager.contains("foo"));
assertEq(serviceManager.totalAlerts(), 0);
assertFalse(serviceManager.contains(1, "foo"));
assertEq(serviceManager.totalAlerts(1), 0);
vm.stopPrank();
}

function test_removeAlert_RevertIfNotOwner() public {
test_confirmAlert();
vm.expectRevert("Ownable: caller is not the owner");
serviceManager.removeAlert("foo");
serviceManager.removeAlert(1, "foo");
}

function test_QueryMessageHashes() public {
test_confirmAlert();
bytes32[] memory results = serviceManager.queryMessageHashes(0, 2);
bytes32[] memory results = serviceManager.queryMessageHashes(1, 0, 2);
assertTrue(results.length == 1);
assertTrue(results[0] == "foo");
}

function test_QueryMessageHashes_RevertIfInvalidStartIndex() public {
test_confirmAlert();
vm.expectRevert(InvalidStartIndex.selector);
bytes32[] memory results = serviceManager.queryMessageHashes(1, 2);
bytes32[] memory results = serviceManager.queryMessageHashes(1, 1, 2);
}
}

0 comments on commit d64fa64

Please sign in to comment.