Skip to content

Commit ade0a8f

Browse files
committed
Support SSV API URLs without trailing slashes (#396)
1 parent d1fe243 commit ade0a8f

File tree

5 files changed

+23
-8
lines changed

5 files changed

+23
-8
lines changed

crates/common/src/config/mux.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ async fn fetch_lido_registry_keys(
582582
}
583583

584584
async fn fetch_ssv_pubkeys(
585-
api_url: Url,
585+
mut api_url: Url,
586586
chain: Chain,
587587
node_operator_id: U256,
588588
http_timeout: Duration,
@@ -599,6 +599,15 @@ async fn fetch_ssv_pubkeys(
599599
let mut pubkeys: Vec<BlsPublicKey> = vec![];
600600
let mut page = 1;
601601

602+
// Validate the URL - this appends a trailing slash if missing as efficiently as
603+
// possible
604+
if !api_url.path().ends_with('/') {
605+
match api_url.path_segments_mut() {
606+
Ok(mut segments) => segments.push(""), // Analogous to a trailing slash
607+
Err(_) => bail!("SSV API URL is not a valid base URL"),
608+
};
609+
}
610+
602611
loop {
603612
let route = format!(
604613
"{chain_name}/validators/in_operator/{node_operator_id}?perPage={MAX_PER_PAGE}&page={page}",

crates/common/src/config/pbs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,5 +404,5 @@ pub async fn load_pbs_custom_config<T: DeserializeOwned>() -> Result<(PbsModuleC
404404

405405
/// Default URL for the SSV network API
406406
fn default_ssv_api_url() -> Url {
407-
Url::parse("https://api.ssv.network/api/v4").expect("default URL is valid")
407+
Url::parse("https://api.ssv.network/api/v4/").expect("default URL is valid")
408408
}

tests/src/mock_ssv.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ pub async fn create_mock_ssv_server(
3737
force_timeout: Arc::new(RwLock::new(false)),
3838
});
3939
let router = axum::Router::new()
40-
.route("/{chain_name}/validators/in_operator/{node_operator_id}", get(handle_validators))
40+
.route(
41+
"/api/v4/{chain_name}/validators/in_operator/{node_operator_id}",
42+
get(handle_validators),
43+
)
4144
.route("/big_data", get(handle_big_data))
4245
.with_state(state)
4346
.into_make_service();

tests/tests/pbs_mux.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ async fn test_ssv_network_fetch() -> Result<()> {
2929
// Start the mock server
3030
let port = 30100;
3131
let _server_handle = create_mock_ssv_server(port, None).await?;
32-
let url = Url::parse(&format!("http://localhost:{port}/test_chain/validators/in_operator/1"))
33-
.unwrap();
32+
let url =
33+
Url::parse(&format!("http://localhost:{port}/api/v4/test_chain/validators/in_operator/1"))
34+
.unwrap();
3435
let response =
3536
fetch_ssv_pubkeys_from_url(url, Duration::from_secs(HTTP_TIMEOUT_SECONDS_DEFAULT)).await?;
3637

@@ -100,8 +101,9 @@ async fn test_ssv_network_fetch_timeout() -> Result<()> {
100101
force_timeout: Arc::new(RwLock::new(true)),
101102
};
102103
let server_handle = create_mock_ssv_server(port, Some(state)).await?;
103-
let url = Url::parse(&format!("http://localhost:{port}/test_chain/validators/in_operator/1"))
104-
.unwrap();
104+
let url =
105+
Url::parse(&format!("http://localhost:{port}/api/v4/test_chain/validators/in_operator/1"))
106+
.unwrap();
105107
let response = fetch_ssv_pubkeys_from_url(url, Duration::from_secs(TEST_HTTP_TIMEOUT)).await;
106108

107109
// The response should fail due to timeout

tests/tests/pbs_mux_refresh.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ async fn test_auto_refresh() -> Result<()> {
4242

4343
// Start the mock SSV API server
4444
let ssv_api_port = pbs_port + 1;
45-
let ssv_api_url = Url::parse(&format!("http://localhost:{ssv_api_port}"))?;
45+
// Intentionally missing a trailing slash to ensure this is handled properly
46+
let ssv_api_url = Url::parse(&format!("http://localhost:{ssv_api_port}/api/v4"))?;
4647
let mock_ssv_state = SsvMockState {
4748
validators: Arc::new(RwLock::new(vec![SSVValidator {
4849
pubkey: existing_mux_pubkey.clone(),

0 commit comments

Comments
 (0)