Skip to content

Commit

Permalink
feat(mux): support SSV network (#223)
Browse files Browse the repository at this point in the history
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
  • Loading branch information
ManuelBilbao and ltitanb authored Jan 9, 2025
1 parent 4c370ea commit 76e0134
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
2 changes: 2 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,11 @@ validator_pubkeys = [
# Path to a file containing a list of validator pubkeys or details of a registry to load keys from.
# Supported registries:
# - Lido: NodeOperatorsRegistry
# - SSV: SSV API
# OPTIONAL
loader = "./tests/data/mux_keys.example.json"
# loader = { registry = "lido", node_operator_id = 8 }
# loader = { registry = "ssv", node_operator_id = 8 }
timeout_get_header_ms = 900
late_in_slot_time_ms = 1500
# For each mux, one or more [[mux.relays]] can be defined, which will be used for the matching validator pubkeys
Expand Down
80 changes: 80 additions & 0 deletions crates/common/src/config/mux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ pub enum MuxKeysLoader {
pub enum NORegistry {
#[serde(alias = "lido")]
Lido,
#[serde(alias = "ssv")]
SSV,
}

impl MuxKeysLoader {
Expand Down Expand Up @@ -176,6 +178,7 @@ impl MuxKeysLoader {

fetch_lido_registry_keys(rpc_url, chain, U256::from(*node_operator_id)).await
}
NORegistry::SSV => fetch_ssv_pubkeys(chain, U256::from(*node_operator_id)).await,
},
}
}
Expand Down Expand Up @@ -266,6 +269,71 @@ async fn fetch_lido_registry_keys(
Ok(keys)
}

async fn fetch_ssv_pubkeys(
chain: Chain,
node_operator_id: U256,
) -> eyre::Result<Vec<BlsPublicKey>> {
const MAX_PER_PAGE: usize = 100;

let chain_name = match chain {
Chain::Mainnet => "mainnet",
Chain::Holesky => "holesky",
_ => bail!("SSV network is not supported for chain: {chain:?}"),
};

let client = reqwest::Client::new();
let mut pubkeys: Vec<BlsPublicKey> = vec![];
let mut page = 1;

loop {
let response = client
.get(format!(
"https://api.ssv.network/api/v4/{}/validators/in_operator/{}?perPage={}&page={}",
chain_name, node_operator_id, MAX_PER_PAGE, page
))
.send()
.await
.map_err(|e| eyre::eyre!("Error sending request to SSV network API: {e}"))?
.json::<SSVResponse>()
.await?;

pubkeys.extend(response.validators.iter().map(|v| v.pubkey).collect::<Vec<BlsPublicKey>>());
page += 1;

if response.validators.len() < MAX_PER_PAGE {
ensure!(
pubkeys.len() == response.pagination.total,
"expected {} keys, got {}",
response.pagination.total,
pubkeys.len()
);
break;
}
}

let unique = pubkeys.iter().collect::<HashSet<_>>();
ensure!(unique.len() == pubkeys.len(), "found duplicate keys in registry");

Ok(pubkeys)
}

#[derive(Deserialize)]
struct SSVResponse {
validators: Vec<SSVValidator>,
pagination: SSVPagination,
}

#[derive(Deserialize)]
struct SSVValidator {
#[serde(rename = "public_key")]
pubkey: BlsPublicKey,
}

#[derive(Deserialize)]
struct SSVPagination {
total: usize,
}

#[cfg(test)]
mod tests {
use alloy::{primitives::U256, providers::ProviderBuilder};
Expand Down Expand Up @@ -304,4 +372,16 @@ mod tests {

Ok(())
}

#[tokio::test]
async fn test_ssv_network_fetch() -> eyre::Result<()> {
let chain = Chain::Holesky;
let node_operator_id = U256::from(200);

let pubkeys = fetch_ssv_pubkeys(chain, node_operator_id).await?;

assert_eq!(pubkeys.len(), 3);

Ok(())
}
}
10 changes: 9 additions & 1 deletion examples/configs/pbs_mux.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ id = "timing-mux"
validator_pubkeys = [
"0x80c7f782b2467c5898c5516a8b6595d75623960b4afc4f71ee07d40985d20e117ba35e7cd352a3e75fb85a8668a3b745",
]
loader = "./mux_keys.example.json"
loader = "./tests/data/mux_keys.example.json"
timeout_get_header_ms = 900
late_in_slot_time_ms = 1500

Expand All @@ -38,3 +38,11 @@ loader = { registry = "lido", node_operator_id = 8 }
[[mux.relays]]
id = "relay-3"
url = "http://0x80c7f782b2467c5898c5516a8b6595d75623960b4afc4f71ee07d40985d20e117ba35e7cd352a3e75fb85a8668a3b745@fgh.xyz"

[[mux]]
id = "ssv-mux"
loader = { registry = "ssv", node_operator_id = 200 }

[[mux.relays]]
id = "relay-4"
url = "http://0x80c7f782b2467c5898c5516a8b6595d75623960b4afc4f71ee07d40985d20e117ba35e7cd352a3e75fb85a8668a3b745@fgh.xyz"

0 comments on commit 76e0134

Please sign in to comment.