Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(registry): cheaper on-chain batch opt-in (48k gas) #336

Merged
merged 12 commits into from
Oct 30, 2024
2 changes: 1 addition & 1 deletion bolt-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The Bolt CLI is a collection of command-line tools for interacting with Bolt pro
Prerequisites:

- [Rust toolchain][rust]
- [Protoc][protoc]
- [Protoc][protoc] (as well as `libprotobuf-dev` for some Linux distributions)

Once you have the necessary prerequisites, you can build the binary in the following way:

Expand Down
33 changes: 20 additions & 13 deletions bolt-contracts/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,25 @@ BoltChallengerTest:testProveTransactionInclusion() (gas: 176543)
BoltChallengerTest:testResolveChallengeFullDefenseSingleTx() (gas: 562694)
BoltChallengerTest:testResolveChallengeFullDefenseStackedTxs() (gas: 939716)
BoltChallengerTest:testResolveExpiredChallenge() (gas: 426457)
BoltManagerEigenLayerTest:testDeregisterOperatorFromAVS() (gas: 755578)
BoltManagerEigenLayerTest:testGetOperatorStake() (gas: 919551)
BoltManagerEigenLayerTest:testNonExistentProposerStatus() (gas: 901546)
BoltManagerEigenLayerTest:testProposerStatus() (gas: 928359)
BoltManagerEigenLayerTest:testProposersLookaheadStatus() (gas: 2221042)
BoltManagerSymbioticTest:testGetNonExistentProposerStatus() (gas: 1168685)
BoltManagerSymbioticTest:testGetProposerStatus() (gas: 1415457)
BoltManagerSymbioticTest:testProposersLookaheadStatus() (gas: 2488651)
BoltManagerSymbioticTest:testReadOperatorStake() (gas: 1448345)
BoltValidatorsTest:testUnsafeRegistration() (gas: 149361)
BoltValidatorsTest:testUnsafeRegistrationFailsIfAlreadyRegistered() (gas: 148862)
BoltValidatorsTest:testUnsafeRegistrationInvalidOperator() (gas: 22820)
BoltValidatorsTest:testUnsafeRegistrationWhenNotAllowed() (gas: 33183)
BoltManagerEigenLayerTest:testDeregisterOperatorFromAVS() (gas: 757038)
BoltManagerEigenLayerTest:testGetOperatorStake() (gas: 916622)
BoltManagerEigenLayerTest:testNonExistentProposerStatus() (gas: 902889)
BoltManagerEigenLayerTest:testProposerStatus() (gas: 927230)
BoltManagerEigenLayerTest:testProposersLookaheadStatus() (gas: 2197665)
BoltManagerSymbioticTest:testGetNonExistentProposerStatus() (gas: 1309103)
BoltManagerSymbioticTest:testGetProposerStatus() (gas: 1556603)
BoltManagerSymbioticTest:testProposersLookaheadStatus() (gas: 2632992)
BoltManagerSymbioticTest:testReadOperatorStake() (gas: 1590527)
BoltValidatorsTest:testUnsafeBatchRegistrationGasUsage() (gas: 29088733)
BoltValidatorsTest:testUnsafeRegistration() (gas: 138036)
BoltValidatorsTest:testUnsafeRegistrationFailsIfAlreadyRegistered() (gas: 135421)
BoltValidatorsTest:testUnsafeRegistrationInvalidOperator() (gas: 17352)
BoltValidatorsTest:testUnsafeRegistrationWhenNotAllowed() (gas: 12330)
BoltValidatorsV2Test:testReadRegisteredValidatorsV2() (gas: 8051)
BoltValidatorsV2Test:testUnauthorizedController() (gas: 3613)
BoltValidatorsV2Test:testUnsafeBatchRegistrationV2() (gas: 29122477)
BoltValidatorsV2Test:testUnsafeRegistrationInvalidOperatorV2() (gas: 10332)
BoltValidatorsV2Test:testUnsafeRegistrationV2() (gas: 215472)
BoltValidatorsV2Test:testUpdateMaxGasLimitV2() (gas: 4434)
TransactionDecoderTest:testDecodeAllTestCases() (gas: 0)
TransactionDecoderTest:testDecodeGasUsage() (gas: 53281)
29 changes: 29 additions & 0 deletions bolt-contracts/script/holesky/admin/Upgrade.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {BoltEigenLayerMiddlewareV1} from "../../../src/contracts/BoltEigenLayerM
import {BoltEigenLayerMiddlewareV2} from "../../../src/contracts/BoltEigenLayerMiddlewareV2.sol";
import {BoltSymbioticMiddlewareV1} from "../../../src/contracts/BoltSymbioticMiddlewareV1.sol";
import {BoltSymbioticMiddlewareV2} from "../../../src/contracts/BoltSymbioticMiddlewareV2.sol";
import {BoltValidatorsV1} from "../../../src/contracts/BoltValidatorsV1.sol";
import {BoltValidatorsV2} from "../../../src/contracts/BoltValidatorsV2.sol";
import {BoltConfig} from "../../../src/lib/Config.sol";

contract UpgradeBolt is Script {
struct Deployments {
address boltManager;
address boltParameters;
address boltValidators;
address symbioticNetwork;
address symbioticOperatorRegistry;
address symbioticOperatorNetOptIn;
Expand Down Expand Up @@ -103,6 +106,31 @@ contract UpgradeBolt is Script {
console.log("BoltSymbioticMiddleware proxy upgraded from %s to %s", opts.referenceContract, upgradeTo);
}

function upgradeBoltValidators() public {
address admin = msg.sender;
console.log("Upgrading BoltValidators with admin", admin);
// TODO: Validate upgrades with Upgrades.validateUpgrade
thedevbirb marked this conversation as resolved.
Show resolved Hide resolved

Options memory opts;
opts.unsafeSkipAllChecks = true;
opts.referenceContract = "BoltValidatorsV1.sol";

string memory upgradeTo = "BoltValidatorsV2.sol";

Deployments memory deployments = _readDeployments();

bytes memory initBoltValidators =
abi.encodeCall(BoltValidatorsV2.initializeV2, (admin, deployments.boltParameters));

vm.startBroadcast(admin);

Upgrades.upgradeProxy(deployments.boltValidators, upgradeTo, initBoltValidators, opts);

vm.stopBroadcast();

console.log("BoltValidators proxy upgraded from %s to %s", opts.referenceContract, upgradeTo);
}

function _readDeployments() public view returns (Deployments memory) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/deployments.json");
Expand All @@ -111,6 +139,7 @@ contract UpgradeBolt is Script {
return Deployments({
boltParameters: vm.parseJsonAddress(json, ".bolt.parameters"),
boltManager: vm.parseJsonAddress(json, ".bolt.manager"),
boltValidators: vm.parseJsonAddress(json, ".bolt.validators"),
symbioticNetwork: vm.parseJsonAddress(json, ".symbiotic.network"),
symbioticOperatorRegistry: vm.parseJsonAddress(json, ".symbiotic.operatorRegistry"),
symbioticOperatorNetOptIn: vm.parseJsonAddress(json, ".symbiotic.networkOptInService"),
Expand Down
4 changes: 2 additions & 2 deletions bolt-contracts/script/holesky/admin/helpers/RegisterAVS.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ pragma solidity 0.8.25;

import {Script, console} from "forge-std/Script.sol";

import {BoltEigenLayerMiddlewareV1} from "../../../../src/contracts/BoltEigenLayerMiddlewareV1.sol";
import {BoltEigenLayerMiddlewareV2} from "../../../../src/contracts/BoltEigenLayerMiddlewareV2.sol";

contract RegisterAVS is Script {
function run() public {
address admin = msg.sender;
console.log("Running with admin address:", admin);

BoltEigenLayerMiddlewareV1 middleware = BoltEigenLayerMiddlewareV1(readMiddleware());
BoltEigenLayerMiddlewareV2 middleware = BoltEigenLayerMiddlewareV2(readMiddleware());

string memory avsURI = "https://boltprotocol.xyz/avs.json";
console.log("Setting AVS metadata URI to:", avsURI);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import {Script, console} from "forge-std/Script.sol";
import {INetworkRegistry} from "@symbiotic/interfaces/INetworkRegistry.sol";
import {INetworkMiddlewareService} from "@symbiotic/interfaces/service/INetworkMiddlewareService.sol";

import {BoltSymbioticMiddlewareV1} from "../../../../src/contracts/BoltSymbioticMiddlewareV1.sol";
import {BoltSymbioticMiddlewareV2} from "../../../../src/contracts/BoltSymbioticMiddlewareV2.sol";

contract UpdateSupportedVaults is Script {
function run() public {
BoltSymbioticMiddlewareV1 middleware = _readSymbioticMiddleware();
BoltSymbioticMiddlewareV2 middleware = _readSymbioticMiddleware();

address[] memory whitelisted = middleware.getWhitelistedVaults();
address[] memory toWhitelist = _readVaultsToWhitelist();
Expand Down Expand Up @@ -64,11 +64,11 @@ contract UpdateSupportedVaults is Script {
return vm.parseJsonAddressArray(json, ".symbiotic.supportedVaults");
}

function _readSymbioticMiddleware() public view returns (BoltSymbioticMiddlewareV1) {
function _readSymbioticMiddleware() public view returns (BoltSymbioticMiddlewareV2) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/deployments.json");
string memory json = vm.readFile(path);

return BoltSymbioticMiddlewareV1(vm.parseJsonAddress(json, ".symbiotic.middleware"));
return BoltSymbioticMiddlewareV2(vm.parseJsonAddress(json, ".symbiotic.middleware"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {IStrategyManager} from "@eigenlayer/src/contracts/interfaces/IStrategyMa
import {IStrategy, IERC20} from "@eigenlayer/src/contracts/interfaces/IStrategy.sol";
import {ISignatureUtils} from "@eigenlayer/src/contracts/interfaces/ISignatureUtils.sol";

import {BoltEigenLayerMiddlewareV1} from "../../../src/contracts/BoltEigenLayerMiddlewareV1.sol";
import {BoltEigenLayerMiddlewareV2} from "../../../src/contracts/BoltEigenLayerMiddlewareV2.sol";
import {IBoltMiddlewareV1} from "../../../src/interfaces/IBoltMiddlewareV1.sol";
import {IBoltManagerV1} from "../../../src/interfaces/IBoltManagerV1.sol";
import {IBoltManagerV2} from "../../../src/interfaces/IBoltManagerV2.sol";

contract RegisterEigenLayerOperator is Script {
struct OperatorConfig {
Expand Down Expand Up @@ -43,7 +43,7 @@ contract RegisterEigenLayerOperator is Script {
uint256 operatorSk = vm.envUint("OPERATOR_SK");
address operator = vm.addr(operatorSk);

BoltEigenLayerMiddlewareV1 middleware = _readMiddleware();
BoltEigenLayerMiddlewareV2 middleware = _readMiddleware();
IAVSDirectory avsDirectory = _readAvsDirectory();
OperatorConfig memory config = _readConfig("config/holesky/operators/eigenlayer/registerIntoBoltAVS.json");

Expand Down Expand Up @@ -76,12 +76,12 @@ contract RegisterEigenLayerOperator is Script {
address operatorAddress = vm.envAddress("OPERATOR_ADDRESS");
console.log("Checking operator registration for address", operatorAddress);

IBoltManagerV1 boltManager = _readBoltManager();
IBoltManagerV2 boltManager = _readBoltManager();
bool isRegistered = boltManager.isOperator(operatorAddress);
console.log("Operator is registered:", isRegistered);
require(isRegistered, "Operator is not registered");

BoltEigenLayerMiddlewareV1 middleware = _readMiddleware();
BoltEigenLayerMiddlewareV2 middleware = _readMiddleware();
(address[] memory tokens, uint256[] memory amounts) = middleware.getOperatorCollaterals(operatorAddress);

for (uint256 i; i < tokens.length; ++i) {
Expand All @@ -91,12 +91,12 @@ contract RegisterEigenLayerOperator is Script {
}
}

function _readMiddleware() public view returns (BoltEigenLayerMiddlewareV1) {
function _readMiddleware() public view returns (BoltEigenLayerMiddlewareV2) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/deployments.json");
string memory json = vm.readFile(path);

return BoltEigenLayerMiddlewareV1(vm.parseJsonAddress(json, ".eigenLayer.middleware"));
return BoltEigenLayerMiddlewareV2(vm.parseJsonAddress(json, ".eigenLayer.middleware"));
}

function _readAvsDirectory() public view returns (IAVSDirectory) {
Expand All @@ -122,11 +122,11 @@ contract RegisterEigenLayerOperator is Script {
return IStrategyManager(vm.parseJsonAddress(json, ".eigenLayer.strategyManager"));
}

function _readBoltManager() public view returns (IBoltManagerV1) {
function _readBoltManager() public view returns (IBoltManagerV2) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/deployments.json");
string memory json = vm.readFile(path);
return IBoltManagerV1(vm.parseJsonAddress(json, ".bolt.manager"));
return IBoltManagerV2(vm.parseJsonAddress(json, ".bolt.manager"));
}

function _readConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ pragma solidity 0.8.25;

import {Script, console} from "forge-std/Script.sol";

import {BoltSymbioticMiddlewareV1} from "../../../src/contracts/BoltSymbioticMiddlewareV1.sol";
import {IBoltManagerV1} from "../../../src/interfaces/IBoltManagerV1.sol";
import {BoltSymbioticMiddlewareV2} from "../../../src/contracts/BoltSymbioticMiddlewareV2.sol";
import {IBoltManagerV2} from "../../../src/interfaces/IBoltManagerV2.sol";

import {IOptInService} from "@symbiotic/interfaces/service/IOptInService.sol";
import {IVault} from "@symbiotic/interfaces/vault/IVault.sol";

contract RegisterSymbioticOperator is Script {
struct Config {
BoltSymbioticMiddlewareV1 symbioticMiddleware;
BoltSymbioticMiddlewareV2 symbioticMiddleware;
IOptInService symbioticNetworkOptInService;
address symbioticNetwork;
}
Expand Down Expand Up @@ -54,7 +54,7 @@ contract RegisterSymbioticOperator is Script {
address operatorAddress = vm.envAddress("OPERATOR_ADDRESS");
console.log("Checking operator registration for address", operatorAddress);

IBoltManagerV1 boltManager = _readBoltManager();
IBoltManagerV2 boltManager = _readBoltManager();
bool isRegistered = boltManager.isOperator(operatorAddress);

console.log("Operator is registered:", isRegistered);
Expand All @@ -68,15 +68,15 @@ contract RegisterSymbioticOperator is Script {

return Config({
symbioticNetwork: vm.parseJsonAddress(json, ".symbiotic.network"),
symbioticMiddleware: BoltSymbioticMiddlewareV1(vm.parseJsonAddress(json, ".symbiotic.middleware")),
symbioticMiddleware: BoltSymbioticMiddlewareV2(vm.parseJsonAddress(json, ".symbiotic.middleware")),
symbioticNetworkOptInService: IOptInService(vm.parseJsonAddress(json, ".symbiotic.networkOptInService"))
});
}

function _readBoltManager() public view returns (IBoltManagerV1) {
function _readBoltManager() public view returns (IBoltManagerV2) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/deployments.json");
string memory json = vm.readFile(path);
return IBoltManagerV1(vm.parseJsonAddress(json, ".bolt.manager"));
return IBoltManagerV2(vm.parseJsonAddress(json, ".bolt.manager"));
}
}
68 changes: 47 additions & 21 deletions bolt-contracts/script/holesky/validators/RegisterValidators.s.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IBoltValidatorsV1} from "../../../src/interfaces/IBoltValidatorsV1.sol";
import {IBoltValidatorsV2} from "../../../src/interfaces/IBoltValidatorsV2.sol";
import {BLS12381} from "../../../src/lib/bls/BLS12381.sol";

import {Script, console} from "forge-std/Script.sol";
Expand All @@ -12,9 +12,12 @@ contract RegisterValidators is Script {
using BLS12381 for BLS12381.G1Point;

struct RegisterValidatorsConfig {
uint128 maxCommittedGasLimit;
uint32 maxCommittedGasLimit;
address authorizedOperator;
BLS12381.G1Point[] pubkeys;
// Note: for Unsafe registration (aka without BLS verification precompile)
// we use compressed pubkey hashes on-chain instead of decompressed points.
// BLS12381.G1Point[] pubkeys;
bytes20[] pubkeys;
}

function run() public {
Expand All @@ -23,7 +26,7 @@ contract RegisterValidators is Script {
console.log("Registering validators to Bolt");
console.log("Controller address: ", controller);

IBoltValidatorsV1 validators = _readValidators();
IBoltValidatorsV2 validators = _readValidators();
RegisterValidatorsConfig memory config = _parseConfig();

vm.startBroadcast(controller);
Expand All @@ -33,43 +36,66 @@ contract RegisterValidators is Script {
console.log("Validators registered successfully");
}

function _readValidators() public view returns (IBoltValidatorsV1) {
function _readValidators() public view returns (IBoltValidatorsV2) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/deployments.json");
string memory json = vm.readFile(path);

return IBoltValidatorsV1(vm.parseJsonAddress(json, ".bolt.validators"));
return IBoltValidatorsV2(vm.parseJsonAddress(json, ".bolt.validators"));
}

function _parseConfig() public returns (RegisterValidatorsConfig memory config) {
function _parseConfig() public view returns (RegisterValidatorsConfig memory config) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/config/holesky/validators.json");
string memory json = vm.readFile(path);

config.authorizedOperator = vm.parseJsonAddress(json, ".authorizedOperator");
config.maxCommittedGasLimit = uint128(vm.parseJsonUint(json, ".maxCommittedGasLimit"));
config.maxCommittedGasLimit = uint32(vm.parseJsonUint(json, ".maxCommittedGasLimit"));
console.log("Max committed gas limit:", config.maxCommittedGasLimit);

string[] memory pubkeysRaw = vm.parseJsonStringArray(json, ".pubkeys");
BLS12381.G1Point[] memory pubkeys = new BLS12381.G1Point[](pubkeysRaw.length);

// NOTE: for Unsafe registration (aka without BLS verification precompile)
// we use compressed pubkey hashes on-chain instead of decompressed points.
bytes20[] memory pubkeys = new bytes20[](pubkeysRaw.length);
for (uint256 i = 0; i < pubkeysRaw.length; i++) {
string memory pubkey = pubkeysRaw[i];
bytes memory pubkeyBytes = vm.parseBytes(pubkeysRaw[i]);
require(pubkeyBytes.length == 48, "Invalid pubkey length");

// compute the pubkey hash:
// 1. create a 64 byte buffer
// 2. copy the pubkey bytes to the rightmost 48 bytes of the buffer
// 3. hash the buffer
// 4. take the 20 leftmost bytes of the hash as the pubkey hash
bytes memory buffer = new bytes(64);
for (uint256 j = 0; j < 48; j++) {
buffer[j + 16] = pubkeyBytes[j];
}
bytes20 pubkeyHash = bytes20(keccak256(buffer));

pubkeys[i] = pubkeyHash;
console.log("Registering pubkey hash:", vm.toString(abi.encodePacked(pubkeyHash)));
}

string[] memory convertCmd = new string[](2);
convertCmd[0] = "./script/pubkey_to_g1_wrapper.sh";
convertCmd[1] = pubkey;
// BLS12381.G1Point[] memory pubkeys = new BLS12381.G1Point[](pubkeysRaw.length);
// for (uint256 i = 0; i < pubkeysRaw.length; i++) {
// string memory pubkey = pubkeysRaw[i];

bytes memory output = vm.ffi(convertCmd);
string memory outputStr = string(output);
string[] memory array = vm.split(outputStr, ",");
// string[] memory convertCmd = new string[](2);
// convertCmd[0] = "./script/pubkey_to_g1_wrapper.sh";
// convertCmd[1] = pubkey;

uint256[2] memory x = _bytesToParts(vm.parseBytes(array[0]));
uint256[2] memory y = _bytesToParts(vm.parseBytes(array[1]));
// bytes memory output = vm.ffi(convertCmd);
// string memory outputStr = string(output);
// string[] memory array = vm.split(outputStr, ",");

pubkeys[i] = BLS12381.G1Point(x, y);
// uint256[2] memory x = _bytesToParts(vm.parseBytes(array[0]));
// uint256[2] memory y = _bytesToParts(vm.parseBytes(array[1]));

console.log("Registering pubkey:", vm.toString(abi.encodePacked(pubkeys[i].compress())));
}
// pubkeys[i] = BLS12381.G1Point(x, y);

// console.log("Registering pubkey:", vm.toString(abi.encodePacked(pubkeys[i].compress())));
// }

config.pubkeys = pubkeys;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeab

import {MapWithTimeData} from "../lib/MapWithTimeData.sol";
import {IBoltParametersV1} from "../interfaces/IBoltParametersV1.sol";
import {IBoltValidatorsV1} from "../interfaces/IBoltValidatorsV1.sol";
import {IBoltMiddlewareV1} from "../interfaces/IBoltMiddlewareV1.sol";
import {IBoltManagerV1} from "../interfaces/IBoltManagerV1.sol";

Expand Down
Loading
Loading