Skip to content

Commit 9d23f31

Browse files
committed
refactor: switch validator metadata reader to JSON API
Update HttpValidatorMetadataReader to GET /api/v1/validators-metadata and parse a JSON list of ValidatorMetadataItem instead of POSTing a SQL query. Rename DataApiValidatorMetadataReader to HttpValidatorMetadataReader and DEFAULT_DATA_API_URL to DEFAULT_VALIDATOR_METADATA_URL.
1 parent 13ef509 commit 9d23f31

2 files changed

Lines changed: 26 additions & 37 deletions

File tree

controlplane/doublezero-admin/src/cli/sentinel.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use doublezero_sentinel::{
99
multicast_find::{apply_filters, FindFilters},
1010
output::{print_table, OutputOptions},
1111
validator_metadata_reader::{
12-
DataApiValidatorMetadataReader, ValidatorMetadataReader, DEFAULT_DATA_API_URL,
12+
HttpValidatorMetadataReader, ValidatorMetadataReader, DEFAULT_VALIDATOR_METADATA_URL,
1313
},
1414
};
1515
use doublezero_serviceability::pda::get_tenant_pda;
@@ -114,7 +114,7 @@ pub struct FindValidatorMulticastPublishersCommand {
114114
summary: bool,
115115

116116
/// Data API URL for validator metadata.
117-
#[arg(long, value_name = "URL", default_value = DEFAULT_DATA_API_URL)]
117+
#[arg(long, value_name = "URL", default_value = DEFAULT_VALIDATOR_METADATA_URL)]
118118
data_api_url: String,
119119

120120
#[command(flatten)]
@@ -128,7 +128,7 @@ impl FindValidatorMulticastPublishersCommand {
128128

129129
let codes = dz_ledger_reader::fetch_device_codes(rpc_client, &program_id).ok();
130130

131-
let validator_metadata = DataApiValidatorMetadataReader {
131+
let validator_metadata = HttpValidatorMetadataReader {
132132
api_url: self.data_api_url.clone(),
133133
};
134134
let dz_ledger = RpcDzLedgerReader::new(
@@ -405,7 +405,7 @@ pub struct CreateValidatorMulticastPublishersCommand {
405405
client: Option<String>,
406406

407407
/// Data API URL for validator metadata.
408-
#[arg(long, value_name = "URL", default_value = DEFAULT_DATA_API_URL)]
408+
#[arg(long, value_name = "URL", default_value = DEFAULT_VALIDATOR_METADATA_URL)]
409409
data_api_url: String,
410410

411411
/// Simulate transactions without sending.
@@ -424,7 +424,7 @@ impl CreateValidatorMulticastPublishersCommand {
424424

425425
let codes = dz_ledger_reader::fetch_device_codes(rpc_client, &program_id).ok();
426426

427-
let validator_metadata = DataApiValidatorMetadataReader {
427+
let validator_metadata = HttpValidatorMetadataReader {
428428
api_url: self.data_api_url.clone(),
429429
};
430430
let dz_ledger = RpcDzLedgerReader::new(

crates/sentinel/src/validator_metadata_reader.rs

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,68 +32,57 @@ pub trait ValidatorMetadataReader: Send + Sync {
3232
// HTTP implementation
3333
// ---------------------------------------------------------------------------
3434

35-
pub const DEFAULT_DATA_API_URL: &str = "https://data.malbeclabs.com/api/sql/query";
35+
pub const DEFAULT_VALIDATOR_METADATA_URL: &str =
36+
"https://data.malbeclabs.com/api/v1/validators-metadata";
3637

37-
pub struct DataApiValidatorMetadataReader {
38+
pub struct HttpValidatorMetadataReader {
3839
pub api_url: String,
3940
}
4041

4142
#[derive(serde::Deserialize)]
42-
struct SqlResponse {
43-
rows: Vec<Vec<serde_json::Value>>,
43+
struct ValidatorMetadataItem {
44+
ip: String,
45+
active_stake: i64,
46+
vote_account: String,
47+
software_client: String,
48+
software_version: String,
4449
}
4550

4651
#[async_trait::async_trait]
47-
impl ValidatorMetadataReader for DataApiValidatorMetadataReader {
52+
impl ValidatorMetadataReader for HttpValidatorMetadataReader {
4853
async fn fetch_validators(&self) -> Result<HashMap<Ipv4Addr, ValidatorRecord>> {
49-
let query = r#"
50-
SELECT
51-
v.vote_account,
52-
v.software_client,
53-
v.software_version,
54-
v.active_stake,
55-
v.ip
56-
FROM validatorsapp_validators_current v
57-
WHERE v.is_active = 1
58-
"#;
59-
6054
let client = reqwest::Client::new();
6155
let resp = client
62-
.post(&self.api_url)
63-
.json(&serde_json::json!({ "query": query }))
56+
.get(&self.api_url)
6457
.send()
6558
.await
66-
.context("failed to query data API for validators")?;
59+
.context("failed to fetch validator metadata")?;
6760

6861
let status = resp.status();
6962
if !status.is_success() {
7063
let body = resp.text().await.unwrap_or_default();
71-
bail!("data API returned {status}: {body}");
64+
bail!("validator metadata service returned {status}: {body}");
7265
}
7366

74-
let body: SqlResponse = resp
67+
let items: Vec<ValidatorMetadataItem> = resp
7568
.json()
7669
.await
77-
.context("failed to parse data API response")?;
70+
.context("failed to parse validator metadata response")?;
7871

7972
let mut map = HashMap::new();
80-
for row in &body.rows {
81-
if row.len() < 5 {
82-
continue;
83-
}
84-
85-
let gossip_ip: Ipv4Addr = match row[4].as_str().unwrap_or_default().parse() {
73+
for item in items {
74+
let gossip_ip: Ipv4Addr = match item.ip.parse() {
8675
Ok(ip) => ip,
8776
Err(_) => continue,
8877
};
8978

9079
map.insert(
9180
gossip_ip,
9281
ValidatorRecord {
93-
vote_account: row[0].as_str().unwrap_or_default().to_string(),
94-
software_client: row[1].as_str().unwrap_or_default().to_string(),
95-
software_version: row[2].as_str().unwrap_or_default().to_string(),
96-
activated_stake_sol: row[3].as_i64().unwrap_or(0) as f64 / 1_000_000_000.0,
82+
vote_account: item.vote_account,
83+
software_client: item.software_client,
84+
software_version: item.software_version,
85+
activated_stake_sol: item.active_stake as f64 / 1_000_000_000.0,
9786
gossip_ip,
9887
},
9988
);

0 commit comments

Comments
 (0)