diff --git a/bolt-contracts/src/contracts/BoltValidators.sol b/bolt-contracts/src/contracts/BoltValidators.sol index 9f4935c0..086de034 100644 --- a/bolt-contracts/src/contracts/BoltValidators.sol +++ b/bolt-contracts/src/contracts/BoltValidators.sol @@ -77,6 +77,8 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, Ownable { } /// @notice Get a validator by its BLS public key + /// @param pubkey BLS public key of the validator + /// @return Validator memory Validator struct function getValidatorByPubkey( BLS12381.G1Point calldata pubkey ) public view returns (Validator memory) { @@ -110,49 +112,54 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, Ownable { /// @notice Register a single Validator and authorize a Collateral Provider and Operator for it /// @dev This function allows anyone to register a single Validator. We do not perform any checks. + /// @param pubkey BLS public key for the Validator to be registered + /// @param maxCommittedGasLimit The maximum gas that the Validator can commit for preconfirmations + /// @param authorizedOperator The address of the authorized operator function registerValidatorUnsafe( BLS12381.G1Point calldata pubkey, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) public { if (!ALLOW_UNSAFE_REGISTRATION) { revert UnsafeRegistrationNotAllowed(); } - _registerValidator(pubkey, nextValidatorSequenceNumber, authorizedCollateralProvider, authorizedOperator); + _registerValidator(pubkey, nextValidatorSequenceNumber, maxCommittedGasLimit, authorizedOperator); } /// @notice Register a single Validator and authorize a Collateral Provider and Operator for it /// @dev This function allows anyone to register a single Validator. We perform an important check: /// The owner of the Validator (controller) must have signed the message with its BLS private key. + /// + /// Message format: `chainId || controller || sequenceNumber` /// @param pubkey BLS public key for the Validator to be registered /// @param signature BLS signature of the registration message for the Validator - /// @param authorizedCollateralProvider The address of the authorized collateral provider + /// @param maxCommittedGasLimit The maximum gas that the Validator can commit for preconfirmations /// @param authorizedOperator The address of the authorized operator function registerValidator( BLS12381.G1Point calldata pubkey, BLS12381.G2Point calldata signature, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) public { bytes memory message = abi.encodePacked(block.chainid, msg.sender, nextValidatorSequenceNumber); if (!_verifySignature(message, signature, pubkey)) { - revert InvalidAuthorizedCollateralProvider(); + revert InvalidBLSSignature(); } - _registerValidator(pubkey, nextValidatorSequenceNumber, authorizedCollateralProvider, authorizedOperator); + _registerValidator(pubkey, nextValidatorSequenceNumber, maxCommittedGasLimit, authorizedOperator); } /// @notice Register a batch of Validators and authorize a Collateral Provider and Operator for them /// @dev This function allows anyone to register a list of Validators. /// @param pubkeys List of BLS public keys for the Validators to be registered /// @param signature BLS aggregated signature of the registration message for this batch of Validators - /// @param authorizedCollateralProvider The address of the authorized collateral provider + /// @param maxCommittedGasLimit The maximum gas that the Validator can commit for preconfirmations /// @param authorizedOperator The address of the authorized operator function batchRegisterValidators( BLS12381.G1Point[] calldata pubkeys, BLS12381.G2Point calldata signature, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) public { uint256 validatorsCount = pubkeys.length; @@ -176,7 +183,7 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, Ownable { // Register the validators and authorize the Collateral Provider and Operator for them for (uint256 i = 0; i < validatorsCount; i++) { _registerValidator( - pubkeys[i], expectedValidatorSequenceNumbers[i], authorizedCollateralProvider, authorizedOperator + pubkeys[i], expectedValidatorSequenceNumbers[i], maxCommittedGasLimit, authorizedOperator ); } } @@ -184,11 +191,11 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, Ownable { /// @notice Register a batch of Validators and authorize a Collateral Provider and Operator for them /// @dev This function allows anyone to register a list of Validators. /// @param pubkeys List of BLS public keys for the Validators to be registered - /// @param authorizedCollateralProvider The address of the authorized collateral provider + /// @param maxCommittedGasLimit The maximum gas that the Validator can commit for preconfirmations /// @param authorizedOperator The address of the authorized operator function batchRegisterValidatorsUnsafe( BLS12381.G1Point[] calldata pubkeys, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) public { if (!ALLOW_UNSAFE_REGISTRATION) { @@ -204,27 +211,44 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, Ownable { // Register the validators and authorize the Collateral Provider and Operator for them for (uint256 i = 0; i < validatorsCount; i++) { _registerValidator( - pubkeys[i], expectedValidatorSequenceNumbers[i], authorizedCollateralProvider, authorizedOperator + pubkeys[i], expectedValidatorSequenceNumbers[i], maxCommittedGasLimit, authorizedOperator ); } } + // ========= UPDATE FUNCTIONS ========= + + /// @notice Update the maximum gas limit that a validator can commit for preconfirmations + /// @dev Only the `controller` of the validator can update this value. + /// @param pubkeyHash The hash of the BLS public key of the validator + /// @param maxCommittedGasLimit The new maximum gas limit + function updateMaxCommittedGasLimit(bytes32 pubkeyHash, uint128 maxCommittedGasLimit) public { + Validator storage validator = VALIDATORS[pubkeyHash]; + + if (!validator.exists) { + revert ValidatorDoesNotExist(); + } + + if (msg.sender != validator.controller) { + revert UnauthorizedCaller(); + } + + validator.maxCommittedGasLimit = maxCommittedGasLimit; + } + // ========= HELPERS ========= /// @notice Internal helper to add a validator to the registry /// @param pubkey BLS public key of the validator /// @param sequenceNumber Sequence number of the validator - /// @param authorizedCollateralProvider Address of the authorized collateral provider + /// @param maxCommittedGasLimit The maximum gas that the Validator can commit for preconfirmations /// @param authorizedOperator Address of the authorized operator function _registerValidator( BLS12381.G1Point calldata pubkey, uint64 sequenceNumber, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) internal { - if (authorizedCollateralProvider == address(0)) { - revert InvalidAuthorizedCollateralProvider(); - } if (authorizedOperator == address(0)) { revert InvalidAuthorizedOperator(); } @@ -238,7 +262,7 @@ contract BoltValidators is IBoltValidators, BLSSignatureVerifier, Ownable { Validator memory newValidator = Validator({ sequenceNumber: sequenceNumber, - authorizedCollateralProvider: authorizedCollateralProvider, + maxCommittedGasLimit: maxCommittedGasLimit, authorizedOperator: authorizedOperator, controller: msg.sender, exists: true diff --git a/bolt-contracts/src/interfaces/IBoltValidators.sol b/bolt-contracts/src/interfaces/IBoltValidators.sol index 0765e747..9c6c040f 100644 --- a/bolt-contracts/src/interfaces/IBoltValidators.sol +++ b/bolt-contracts/src/interfaces/IBoltValidators.sol @@ -5,19 +5,19 @@ import {BLS12381} from "../lib/bls/BLS12381.sol"; import {ValidatorProver} from "../lib/ssz/ValidatorProver.sol"; interface IBoltValidators { - /// @notice Validator + /// @notice Validator info struct Validator { + // whether the validator exists in the registry + bool exists; // the incremental sequence number assigned to the validator uint64 sequenceNumber; - // the entity authorized to deposit collateral for the validator - // to add credibility to its commitments - address authorizedCollateralProvider; + // the maximum amount of gas that the validator can consume with preconfirmations + // in a single slot. Operators must respect this limit when making commitments. + uint128 maxCommittedGasLimit; // the entity authorized to make commitments on behalf of the validator address authorizedOperator; // the EOA that registered the validator and can update its configuration address controller; - // whether the validator exists in the registry - bool exists; } struct ProposerStatus { @@ -34,6 +34,7 @@ interface IBoltValidators { error ValidatorAlreadyExists(); error ValidatorDoesNotExist(); error UnsafeRegistrationNotAllowed(); + error UnauthorizedCaller(); function getAllValidators() external view returns (Validator[] memory); @@ -51,27 +52,29 @@ interface IBoltValidators { function registerValidatorUnsafe( BLS12381.G1Point calldata pubkey, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) external; function registerValidator( BLS12381.G1Point calldata pubkey, BLS12381.G2Point calldata signature, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) external; function batchRegisterValidators( BLS12381.G1Point[] calldata pubkeys, BLS12381.G2Point calldata signature, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) external; function batchRegisterValidatorsUnsafe( BLS12381.G1Point[] calldata pubkeys, - address authorizedCollateralProvider, + uint128 maxCommittedGasLimit, address authorizedOperator ) external; + + function updateMaxCommittedGasLimit(bytes32 pubkeyHash, uint128 maxCommittedGasLimit) external; } diff --git a/bolt-contracts/test/BoltManager.EigenLayer.t.sol b/bolt-contracts/test/BoltManager.EigenLayer.t.sol index 1b06f127..24137586 100644 --- a/bolt-contracts/test/BoltManager.EigenLayer.t.sol +++ b/bolt-contracts/test/BoltManager.EigenLayer.t.sol @@ -29,6 +29,8 @@ contract BoltManagerEigenLayerTest is Test { BoltEigenLayerMiddleware public middleware; EigenLayerDeployer public eigenLayerDeployer; + uint128 public constant PRECONF_MAX_GAS_LIMIT = 5_000_000; + address staker = makeAddr("staker"); address validator = makeAddr("validator"); BLS12381.G1Point validatorPubkey = BLS12381.generatorG1(); @@ -152,10 +154,9 @@ contract BoltManagerEigenLayerTest is Test { validatorPubkey = BLS12381.generatorG1(); vm.prank(validator); - validators.registerValidatorUnsafe(validatorPubkey, staker, operator); + validators.registerValidatorUnsafe(validatorPubkey, PRECONF_MAX_GAS_LIMIT, operator); assertEq(validators.getValidatorByPubkey(validatorPubkey).exists, true); assertEq(validators.getValidatorByPubkey(validatorPubkey).authorizedOperator, operator); - assertEq(validators.getValidatorByPubkey(validatorPubkey).authorizedCollateralProvider, staker); // 2. --- Operator and strategy registration into BoltManager (middleware) --- @@ -209,7 +210,7 @@ contract BoltManagerEigenLayerTest is Test { pubkey.y[0] = pubkey.y[0] + i + 2; pubkeyHashes[i] = _pubkeyHash(pubkey); - validators.registerValidatorUnsafe(pubkey, staker, operator); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, operator); } IBoltValidators.ProposerStatus[] memory statuses = middleware.getProposersStatus(pubkeyHashes); diff --git a/bolt-contracts/test/BoltManager.Symbiotic.t.sol b/bolt-contracts/test/BoltManager.Symbiotic.t.sol index 6306bf91..1601c031 100644 --- a/bolt-contracts/test/BoltManager.Symbiotic.t.sol +++ b/bolt-contracts/test/BoltManager.Symbiotic.t.sol @@ -37,6 +37,8 @@ contract BoltManagerTest is Test { uint48 public constant EPOCH_DURATION = 1 days; uint48 public constant SLASHING_WINDOW = 7 days; + uint128 public constant PRECONF_MAX_GAS_LIMIT = 5_000_000; + BoltValidators public validators; BoltManager public manager; BoltSymbioticMiddleware public middleware; @@ -182,10 +184,9 @@ contract BoltManagerTest is Test { BLS12381.G1Point memory pubkey = BLS12381.generatorG1(); vm.prank(validator); - validators.registerValidatorUnsafe(pubkey, provider, operator); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, operator); assertEq(validators.getValidatorByPubkey(pubkey).exists, true); assertEq(validators.getValidatorByPubkey(pubkey).authorizedOperator, operator); - assertEq(validators.getValidatorByPubkey(pubkey).authorizedCollateralProvider, provider); // --- Register Operator in Symbiotic, opt-in network and vault --- @@ -329,7 +330,7 @@ contract BoltManagerTest is Test { pubkey.y[0] = pubkey.y[0] + i + 2; pubkeyHashes[i] = _pubkeyHash(pubkey); - validators.registerValidatorUnsafe(pubkey, provider, operator); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, operator); } vm.warp(block.timestamp + EPOCH_DURATION * 2 + 1); diff --git a/bolt-contracts/test/BoltValidators.t.sol b/bolt-contracts/test/BoltValidators.t.sol index b4057147..30cefb74 100644 --- a/bolt-contracts/test/BoltValidators.t.sol +++ b/bolt-contracts/test/BoltValidators.t.sol @@ -12,6 +12,8 @@ contract BoltValidatorsTest is Test { BoltValidators public validators; + uint128 public constant PRECONF_MAX_GAS_LIMIT = 5_000_000; + address admin = makeAddr("admin"); address provider = makeAddr("provider"); address operator = makeAddr("operator"); @@ -26,11 +28,11 @@ contract BoltValidatorsTest is Test { BLS12381.G1Point memory pubkey = BLS12381.generatorG1(); vm.prank(validator); - validators.registerValidatorUnsafe(pubkey, provider, operator); + validators.registerValidatorUnsafe(pubkey, 1_000_000, operator); BoltValidators.Validator memory registered = validators.getValidatorByPubkey(pubkey); assertEq(registered.exists, true); - assertEq(registered.authorizedCollateralProvider, provider); + assertEq(registered.maxCommittedGasLimit, 1_000_000); assertEq(registered.authorizedOperator, operator); assertEq(registered.controller, validator); } @@ -39,11 +41,11 @@ contract BoltValidatorsTest is Test { BLS12381.G1Point memory pubkey = BLS12381.generatorG1(); vm.prank(validator); - validators.registerValidatorUnsafe(pubkey, provider, operator); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, operator); vm.prank(validator); vm.expectRevert(IBoltValidators.ValidatorAlreadyExists.selector); - validators.registerValidatorUnsafe(pubkey, provider, operator); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, operator); } function testUnsafeRegistrationWhenNotAllowed() public { @@ -54,15 +56,7 @@ contract BoltValidatorsTest is Test { vm.prank(validator); vm.expectRevert(IBoltValidators.UnsafeRegistrationNotAllowed.selector); - validators.registerValidatorUnsafe(pubkey, provider, operator); - } - - function testUnsafeRegistrationInvalidCollateralProvider() public { - BLS12381.G1Point memory pubkey = BLS12381.generatorG1(); - - vm.prank(validator); - vm.expectRevert(IBoltValidators.InvalidAuthorizedCollateralProvider.selector); - validators.registerValidatorUnsafe(pubkey, address(0), operator); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, operator); } function testUnsafeRegistrationInvalidOperator() public { @@ -70,6 +64,6 @@ contract BoltValidatorsTest is Test { vm.prank(validator); vm.expectRevert(IBoltValidators.InvalidAuthorizedOperator.selector); - validators.registerValidatorUnsafe(pubkey, provider, address(0)); + validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, address(0)); } }