Skip to content

Commit

Permalink
Merge pull request #508 from chainbound/jonas/feat/cli-val-status
Browse files Browse the repository at this point in the history
  • Loading branch information
mempirate authored Dec 2, 2024
2 parents 77cd89e + 0b79bdc commit 9f94497
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
16 changes: 15 additions & 1 deletion bolt-cli/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::path::PathBuf;

use alloy::primitives::{Address, B256, U256};
use alloy::primitives::{Address, FixedBytes, B256, U256};
use clap::{
builder::styling::{AnsiColor, Color, Style},
Parser, Subcommand, ValueEnum,
Expand Down Expand Up @@ -168,6 +168,20 @@ pub enum ValidatorsSubcommand {
#[clap(long, env = "ADMIN_PRIVATE_KEY")]
admin_private_key: B256,
},
/// Check the status of a validator (batch).
Status {
/// The URL of the RPC to broadcast the transaction.
#[clap(long, env = "RPC_URL")]
rpc_url: Url,

/// The path to the JSON pubkeys file, containing an array of BLS public keys.
#[clap(long, env = "PUBKEYS_PATH", conflicts_with = "pubkeys")]
pubkeys_path: Option<PathBuf>,

/// The validator public key to check the status of.
#[clap(long, env = "PUBKEYS", conflicts_with = "pubkeys_path")]
pubkeys: Vec<FixedBytes<48>>,
},
}

#[derive(Debug, Clone, Parser)]
Expand Down
54 changes: 53 additions & 1 deletion bolt-cli/src/commands/validators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use alloy::{
};
use ethereum_consensus::crypto::PublicKey as BlsPublicKey;
use eyre::Context;
use tracing::info;
use tracing::{info, warn};

use crate::{
cli::{Chain, ValidatorsCommand, ValidatorsSubcommand},
Expand Down Expand Up @@ -74,6 +74,46 @@ impl ValidatorsCommand {

info!("Successfully registered validators into bolt");

Ok(())
}
ValidatorsSubcommand::Status { rpc_url, pubkeys_path, pubkeys } => {
let provider = ProviderBuilder::new().on_http(rpc_url);
let chain_id = provider.get_chain_id().await?;
let chain = Chain::from_id(chain_id)
.unwrap_or_else(|| panic!("chain id {} not supported", chain_id));
let registry = deployments_for_chain(chain).bolt.validators;

let mut bls_pubkeys = Vec::new();

if let Some(pubkeys_path) = pubkeys_path {
let pubkeys_file = std::fs::File::open(&pubkeys_path)?;
let keys: Vec<BlsPublicKey> = serde_json::from_reader(pubkeys_file)?;
bls_pubkeys.extend(keys);
}

for bytes in pubkeys {
let key = BlsPublicKey::try_from(bytes.as_ref())?;
bls_pubkeys.push(key);
}

info!(pubkeys = bls_pubkeys.len(), %registry, ?chain, "Checking status of validators");

let pubkey_hashes: Vec<_> = bls_pubkeys.iter().map(compress_bls_pubkey).collect();

let bolt_validators = BoltValidators::new(registry, provider);

for (hash, pubkey) in pubkey_hashes.iter().zip(bls_pubkeys.iter()) {
match bolt_validators.getValidatorByPubkeyHash(*hash).call().await.map(|v| v._0)
{
Ok(info) => {
info!(%pubkey, operator = %info.authorizedOperator, controller = %info.controller, gas_limit = info.maxCommittedGasLimit, "Validator registered");
}
Err(_e) => {
warn!(%pubkey, "Validator not registered");
}
}
}

Ok(())
}
}
Expand All @@ -94,6 +134,8 @@ mod tests {

#[tokio::test]
async fn test_register_validators() {
let _ = tracing_subscriber::fmt::try_init();

let rpc_url = "https://holesky.drpc.org";
let anvil = Anvil::default().fork(rpc_url).spawn();
let anvil_url = Url::parse(&anvil.endpoint()).expect("valid URL");
Expand All @@ -111,7 +153,17 @@ mod tests {
admin_private_key: B256::try_from(secret_key.to_bytes().as_slice()).unwrap(),
authorized_operator: account,
pubkeys_path: "./test_data/pubkeys.json".parse().unwrap(),
rpc_url: anvil_url.clone(),
},
};

command.run().await.expect("run command");

let command = ValidatorsCommand {
subcommand: ValidatorsSubcommand::Status {
rpc_url: anvil_url,
pubkeys_path: Some("./test_data/pubkeys.json".parse().unwrap()),
pubkeys: Vec::new(),
},
};

Expand Down
14 changes: 14 additions & 0 deletions bolt-cli/src/contracts/bolt.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
use alloy::sol;
use serde::Serialize;

sol! {
#[allow(missing_docs)]
#[sol(rpc)]
interface BoltValidators {
#[derive(Debug, Serialize)]
struct ValidatorInfo {
bytes20 pubkeyHash;
uint32 maxCommittedGasLimit;
address authorizedOperator;
address controller;
}

/// @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 pubkeyHashes List of BLS public key hashes for the Validators to be registered
/// @param maxCommittedGasLimit The maximum gas that the Validator can commit for preconfirmations
/// @param authorizedOperator The address of the authorized operator
function batchRegisterValidatorsUnsafe(bytes20[] calldata pubkeyHashes, uint32 maxCommittedGasLimit, address authorizedOperator);

/// @notice Get a validator by its BLS public key hash
/// @param pubkeyHash BLS public key hash of the validator
/// @return ValidatorInfo struct
function getValidatorByPubkeyHash(bytes20 pubkeyHash) public view returns (ValidatorInfo memory);

error KeyNotFound();
error InvalidQuery();
#[derive(Debug)]
Expand Down

0 comments on commit 9f94497

Please sign in to comment.