Skip to content

Commit

Permalink
Merge branch 'nico/feat/commitment-registry' of github.com:chainbound…
Browse files Browse the repository at this point in the history
…/bolt into nico/feat/commitment-registry
  • Loading branch information
merklefruit committed Oct 2, 2024
2 parents 5685566 + ade1063 commit b764a8e
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 48 deletions.
60 changes: 42 additions & 18 deletions bolt-contracts/src/contracts/BoltValidators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -176,19 +183,19 @@ 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
);
}
}

/// @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) {
Expand All @@ -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();
}
Expand All @@ -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
Expand Down
23 changes: 13 additions & 10 deletions bolt-contracts/src/interfaces/IBoltValidators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ pragma solidity 0.8.25;
import {BLS12381} from "../lib/bls/BLS12381.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 {
Expand All @@ -33,6 +33,7 @@ interface IBoltValidators {
error ValidatorAlreadyExists();
error ValidatorDoesNotExist();
error UnsafeRegistrationNotAllowed();
error UnauthorizedCaller();

function getAllValidators() external view returns (Validator[] memory);

Expand All @@ -50,27 +51,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;
}
7 changes: 4 additions & 3 deletions bolt-contracts/test/BoltManager.EigenLayer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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) ---

Expand Down Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions bolt-contracts/test/BoltManager.Symbiotic.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 ---

Expand Down Expand Up @@ -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);
Expand Down
22 changes: 8 additions & 14 deletions bolt-contracts/test/BoltValidators.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);
}
Expand All @@ -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 {
Expand All @@ -54,22 +56,14 @@ 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 {
BLS12381.G1Point memory pubkey = BLS12381.generatorG1();

vm.prank(validator);
vm.expectRevert(IBoltValidators.InvalidAuthorizedOperator.selector);
validators.registerValidatorUnsafe(pubkey, provider, address(0));
validators.registerValidatorUnsafe(pubkey, PRECONF_MAX_GAS_LIMIT, address(0));
}
}

0 comments on commit b764a8e

Please sign in to comment.