From 3fc33d29e3f62eb8bd2a4933adb6e09673650965 Mon Sep 17 00:00:00 2001 From: noel Date: Tue, 14 May 2024 01:23:46 +0900 Subject: [PATCH] test: MachServiceManager --- contracts/test/AVSDeployer.sol | 7 +- contracts/test/BLSAVSDeployer.sol | 164 ++++++++++++++++++++++++ contracts/test/MachServiceManager.t.sol | 121 +++++------------ 3 files changed, 203 insertions(+), 89 deletions(-) create mode 100644 contracts/test/BLSAVSDeployer.sol diff --git a/contracts/test/AVSDeployer.sol b/contracts/test/AVSDeployer.sol index 98bcff6..d59d13c 100644 --- a/contracts/test/AVSDeployer.sol +++ b/contracts/test/AVSDeployer.sol @@ -76,7 +76,8 @@ contract AVSDeployer is Test { /// @notice StakeRegistry, Constant used as a divisor in calculating weights. uint256 public constant WEIGHTING_DIVISOR = 1e18; - address public proxyAdminOwner = address(uint160(uint256(keccak256("proxyAdminOwner")))); + address public proxyAdminOwner = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; + // address public proxyAdminOwner = address(uint160(uint256(keccak256("proxyAdminOwner")))); address public registryCoordinatorOwner = address(uint160(uint256(keccak256("registryCoordinatorOwner")))); address public pauser = address(uint160(uint256(keccak256("pauser")))); address public unpauser = address(uint160(uint256(keccak256("unpauser")))); @@ -100,12 +101,12 @@ contract AVSDeployer is Test { uint32 defaultMaxOperatorCount = 10; uint16 defaultKickBIPsOfOperatorStake = 15000; uint16 defaultKickBIPsOfTotalStake = 150; - uint8 numQuorums = 192; + uint8 numQuorums = 1; IRegistryCoordinator.OperatorSetParam[] operatorSetParams; uint8 maxQuorumsToRegisterFor = 4; - uint256 maxOperatorsToRegister = 4; + uint256 maxOperatorsToRegister = 10; uint32 registrationBlockNumber = 100; uint32 blocksBetweenRegistrations = 10; diff --git a/contracts/test/BLSAVSDeployer.sol b/contracts/test/BLSAVSDeployer.sol new file mode 100644 index 0000000..c256ce0 --- /dev/null +++ b/contracts/test/BLSAVSDeployer.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import {BLSSignatureChecker} from "eigenlayer-middleware/BLSSignatureChecker.sol"; +import {BN254} from "eigenlayer-middleware/libraries/BN254.sol"; +import {OperatorStateRetriever} from "eigenlayer-middleware/OperatorStateRetriever.sol"; +import {BitmapUtils} from "eigenlayer-middleware/libraries/BitmapUtils.sol"; +import {AVSDeployer} from "./AVSDeployer.sol"; + +contract BLSAVSDeployer is AVSDeployer { + using BN254 for BN254.G1Point; + + bytes32 msgHash; + uint256 aggSignerPrivKey = 69; + BN254.G2Point aggSignerApkG2; + BN254.G2Point oneHundredQuorumApkG2; + BN254.G1Point sigma; + + function _setUpBLSMockAVSDeployer() public virtual { + _deployMockEigenLayerAndAVS(); + _setAggregatePublicKeysAndSignature(); + } + + function _setUpBLSMockAVSDeployer(uint8 numQuorumsToAdd) public virtual { + _deployMockEigenLayerAndAVS(numQuorumsToAdd); + _setAggregatePublicKeysAndSignature(); + } + + function _setAggregatePublicKeysAndSignature() internal { + // aggSignerPrivKey*g2 + aggSignerApkG2.X[1] = 19101821850089705274637533855249918363070101489527618151493230256975900223847; + aggSignerApkG2.X[0] = 5334410886741819556325359147377682006012228123419628681352847439302316235957; + aggSignerApkG2.Y[1] = 354176189041917478648604979334478067325821134838555150300539079146482658331; + aggSignerApkG2.Y[0] = 4185483097059047421902184823581361466320657066600218863748375739772335928910; + + // 100*aggSignerPrivKey*g2 + oneHundredQuorumApkG2.X[1] = 6187649255575786743153792867265230878737103598736372524337965086852090105771; + oneHundredQuorumApkG2.X[0] = 5334877400925935887383922877430837542135722474116902175395820705628447222839; + oneHundredQuorumApkG2.Y[1] = 4668116328019846503695710811760363536142902258271850958815598072072236299223; + oneHundredQuorumApkG2.Y[0] = 21446056442597180561077194011672151329458819211586246807143487001691968661015; + + sigma = BN254.hashToG1(msgHash).scalar_mul(aggSignerPrivKey); + } + + function _generateSignerAndNonSignerPrivateKeys( + uint256 pseudoRandomNumber, + uint256 numSigners, + uint256 numNonSigners + ) internal view returns (uint256[] memory, uint256[] memory) { + uint256[] memory signerPrivateKeys = new uint256[](numSigners); + // generate numSigners numbers that add up to aggSignerPrivKey mod BN254.FR_MODULUS + uint256 sum = 0; + for (uint256 i = 0; i < numSigners - 1; i++) { + signerPrivateKeys[i] = + uint256(keccak256(abi.encodePacked("signerPrivateKey", pseudoRandomNumber, i))) % BN254.FR_MODULUS; + sum = addmod(sum, signerPrivateKeys[i], BN254.FR_MODULUS); + } + // signer private keys need to add to aggSignerPrivKey + signerPrivateKeys[numSigners - 1] = + addmod(aggSignerPrivKey, BN254.FR_MODULUS - sum % BN254.FR_MODULUS, BN254.FR_MODULUS); + + uint256[] memory nonSignerPrivateKeys = new uint256[](numNonSigners); + for (uint256 i = 0; i < numNonSigners; i++) { + nonSignerPrivateKeys[i] = + uint256(keccak256(abi.encodePacked("nonSignerPrivateKey", pseudoRandomNumber, i))) % BN254.FR_MODULUS; + } + + // Sort nonSignerPrivateKeys in order of ascending pubkeyHash + // Uses insertion sort to sort array in place + for (uint256 i = 1; i < nonSignerPrivateKeys.length; i++) { + uint256 privateKey = nonSignerPrivateKeys[i]; + bytes32 pubkeyHash = _toPubkeyHash(privateKey); + uint256 j = i; + + // Move elements of nonSignerPrivateKeys[0..i-1] that are greater than the current key + // to one position ahead of their current position + while (j > 0 && _toPubkeyHash(nonSignerPrivateKeys[j - 1]) > pubkeyHash) { + nonSignerPrivateKeys[j] = nonSignerPrivateKeys[j - 1]; + j--; + } + nonSignerPrivateKeys[j] = privateKey; + } + + return (signerPrivateKeys, nonSignerPrivateKeys); + } + + function _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + uint256 pseudoRandomNumber, + uint256 numNonSigners, + uint256 quorumBitmap + ) internal returns (uint32, BLSSignatureChecker.NonSignerStakesAndSignature memory) { + (uint256[] memory signerPrivateKeys, uint256[] memory nonSignerPrivateKeys) = + _generateSignerAndNonSignerPrivateKeys( + pseudoRandomNumber, maxOperatorsToRegister - numNonSigners, numNonSigners + ); + bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); + + // randomly combine signer and non-signer private keys + uint256[] memory privateKeys = new uint256[](maxOperatorsToRegister); + // generate addresses and public keys + address[] memory operators = new address[](maxOperatorsToRegister); + BN254.G1Point[] memory pubkeys = new BN254.G1Point[](maxOperatorsToRegister); + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature; + nonSignerStakesAndSignature.quorumApks = new BN254.G1Point[](quorumNumbers.length); + nonSignerStakesAndSignature.nonSignerPubkeys = new BN254.G1Point[](numNonSigners); + bytes32[] memory nonSignerOperatorIds = new bytes32[](numNonSigners); + { + uint256 signerIndex = 0; + uint256 nonSignerIndex = 0; + for (uint256 i = 0; i < maxOperatorsToRegister; i++) { + uint256 randomSeed = uint256(keccak256(abi.encodePacked("privKeyCombination", i))); + if (randomSeed % 2 == 0 && signerIndex < signerPrivateKeys.length) { + privateKeys[i] = signerPrivateKeys[signerIndex]; + signerIndex++; + } else if (nonSignerIndex < nonSignerPrivateKeys.length) { + privateKeys[i] = nonSignerPrivateKeys[nonSignerIndex]; + nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex] = + BN254.generatorG1().scalar_mul(privateKeys[i]); + nonSignerOperatorIds[nonSignerIndex] = + nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex].hashG1Point(); + nonSignerIndex++; + } else { + privateKeys[i] = signerPrivateKeys[signerIndex]; + signerIndex++; + } + + operators[i] = _incrementAddress(defaultOperator, i); + pubkeys[i] = BN254.generatorG1().scalar_mul(privateKeys[i]); + + // add the public key to each quorum + for (uint256 j = 0; j < nonSignerStakesAndSignature.quorumApks.length; j++) { + nonSignerStakesAndSignature.quorumApks[j] = + nonSignerStakesAndSignature.quorumApks[j].plus(pubkeys[i]); + } + } + } + + // register all operators for the first quorum + for (uint256 i = 0; i < maxOperatorsToRegister; i++) { + cheats.roll(registrationBlockNumber + blocksBetweenRegistrations * i); + _registerOperatorWithCoordinator(operators[i], quorumBitmap, pubkeys[i], defaultStake); + } + + uint32 referenceBlockNumber = + registrationBlockNumber + blocksBetweenRegistrations * uint32(maxOperatorsToRegister) + 1; + cheats.roll(referenceBlockNumber + 100); + + OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever + .getCheckSignaturesIndices(registryCoordinator, referenceBlockNumber, quorumNumbers, nonSignerOperatorIds); + + nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices = checkSignaturesIndices.nonSignerQuorumBitmapIndices; + nonSignerStakesAndSignature.apkG2 = aggSignerApkG2; + nonSignerStakesAndSignature.sigma = sigma; + nonSignerStakesAndSignature.quorumApkIndices = checkSignaturesIndices.quorumApkIndices; + nonSignerStakesAndSignature.totalStakeIndices = checkSignaturesIndices.totalStakeIndices; + nonSignerStakesAndSignature.nonSignerStakeIndices = checkSignaturesIndices.nonSignerStakeIndices; + + return (referenceBlockNumber, nonSignerStakesAndSignature); + } + + function _toPubkeyHash(uint256 privKey) internal view returns (bytes32) { + return BN254.generatorG1().scalar_mul(privKey).hashG1Point(); + } +} diff --git a/contracts/test/MachServiceManager.t.sol b/contracts/test/MachServiceManager.t.sol index 70596bb..4c5c591 100644 --- a/contracts/test/MachServiceManager.t.sol +++ b/contracts/test/MachServiceManager.t.sol @@ -1,115 +1,64 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.12; -import "./AVSDeployer.sol"; +import "forge-std/Test.sol"; + +import "./BLSAVSDeployer.sol"; import "../src/error/Errors.sol"; +import "../src/interfaces/IMachServiceManager.sol"; -contract MachServiceManagerTest is AVSDeployer { +contract MachServiceManagerTest is BLSAVSDeployer { event OperatorAllowed(address operator); event OperatorDisallowed(address operator); event AllowlistEnabled(); event AllowlistDisabled(); + event AlertConfirmerChanged(address previousAddress, address newAddress); + event WhitelisterChanged(address previousAddress, address newAddress); + event QuorumThresholdPercentageChanged(uint8 thresholdPercentages); + event RollupChainIdUpdated(uint256 previousRollupChainId, uint256 newRollupChainId); function setUp() public virtual { _deployMockEigenLayerAndAVS(); } - function test_AddToAllowlist() public { - vm.startPrank(proxyAdminOwner); - assertFalse(serviceManager.allowlist(defaultOperator), "mismatch"); - vm.expectEmit(); - emit OperatorAllowed(defaultOperator); - serviceManager.addToAllowlist(defaultOperator); - assertTrue(serviceManager.allowlist(defaultOperator), "mismatch"); - vm.stopPrank(); - } - - function test_AddToAllowlist_RevertIfZeroAddress() public { - vm.startPrank(proxyAdminOwner); - vm.expectRevert(ZeroAddress.selector); - serviceManager.addToAllowlist(address(0)); - vm.stopPrank(); - } - - function test_AddToAllowlist_RevertIfAlreadyInAllowlist() public { - test_AddToAllowlist(); - vm.startPrank(proxyAdminOwner); - vm.expectRevert(AlreadyInAllowlist.selector); - serviceManager.addToAllowlist(defaultOperator); - vm.stopPrank(); - } - - function test_RemoveFromAllowlist() public { - test_AddToAllowlist(); - vm.startPrank(proxyAdminOwner); - assertTrue(serviceManager.allowlist(defaultOperator), "Operator should be in allowlist before removal"); - - vm.expectEmit(); - emit OperatorDisallowed(defaultOperator); - - serviceManager.removeFromAllowlist(defaultOperator); - - assertFalse(serviceManager.allowlist(defaultOperator), "Operator should not be in allowlist after removal"); - vm.stopPrank(); - } - - function test_RemoveFromAllowlist_RevertIfNotInAllowlist() public { - address nonListedOperator = address(0xdead); - + function test_confirmAlert() public { vm.startPrank(proxyAdminOwner); - assertFalse(serviceManager.allowlist(nonListedOperator), "Operator should not be in allowlist"); - - vm.expectRevert(NotInAllowlist.selector); - serviceManager.removeFromAllowlist(nonListedOperator); - vm.stopPrank(); - } - - function test_DisableAllowlist() public { - vm.startPrank(proxyAdminOwner); - assertTrue(serviceManager.allowlistEnabled(), "Allowlist should be enabled initially"); - - vm.expectEmit(true, true, true, true); // Check all parameters of the event - emit AllowlistDisabled(); - serviceManager.disableAllowlist(); - - assertFalse(serviceManager.allowlistEnabled(), "Allowlist should be disabled after calling disableAllowlist"); vm.stopPrank(); - } - - function test_DisableAllowlist_RevertIfAlreadyDisabled() public { - vm.startPrank(proxyAdminOwner); - - // First, ensure the allowlist is disabled - serviceManager.disableAllowlist(); - assertFalse(serviceManager.allowlistEnabled(), "Allowlist should already be disabled"); - vm.expectRevert(AlreadyDisabled.selector); // Expect the specific revert for trying to disable an already disabled allowlist - serviceManager.disableAllowlist(); - vm.stopPrank(); - } + uint256 nonRandomNumber = 111; + uint256 numNonSigners = 1; + uint256 quorumBitmap = 1; + bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - function test_EnableAllowlist() public { - vm.startPrank(proxyAdminOwner); + msgHash = keccak256( + abi.encode(IMachServiceManager.ReducedAlertHeader({messageHash: "foo", referenceBlockNumber: 201})) + ); - // First, ensure the allowlist is disabled - serviceManager.disableAllowlist(); + _setAggregatePublicKeysAndSignature(); - assertFalse(serviceManager.allowlistEnabled(), "Allowlist should be disabled initially"); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); - vm.expectEmit(true, true, true, true); // Check all parameters of the event - emit AllowlistEnabled(); + ( + BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, + /* bytes32 signatoryRecordHash */ + ) = serviceManager.checkSignatures(msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature); - serviceManager.enableAllowlist(); + bytes memory quorumThresholdPercentages = new bytes(1); + quorumThresholdPercentages[0] = bytes1(uint8(67)); - assertTrue(serviceManager.allowlistEnabled(), "Allowlist should be enabled after calling enableAllowlist"); - vm.stopPrank(); - } + IMachServiceManager.AlertHeader memory header = IMachServiceManager.AlertHeader({ + messageHash: "foo", + quorumNumbers: quorumNumbers, + quorumThresholdPercentages: quorumThresholdPercentages, + referenceBlockNumber: referenceBlockNumber + }); - function test_EnableAllowlist_RevertIfAlreadyEnabled() public { vm.startPrank(proxyAdminOwner); - vm.expectRevert(AlreadyEnabled.selector); // Expect the specific revert for trying to enable an already enabled allowlist - serviceManager.enableAllowlist(); + serviceManager.confirmAlert(header, nonSignerStakesAndSignature); vm.stopPrank(); } }