wallet: use Urls rather than Strings for validator urls
This commit is contained in:
@@ -100,25 +100,31 @@ impl Config {
|
||||
/// 1. from the configuration file
|
||||
/// 2. provided remotely
|
||||
/// 3. hardcoded fallback
|
||||
pub fn get_validators(
|
||||
&self,
|
||||
network: WalletNetwork,
|
||||
) -> impl Iterator<Item = &ValidatorDetails> + '_ {
|
||||
pub fn get_validators(&self, network: WalletNetwork) -> impl Iterator<Item = ValidatorUrl> + '_ {
|
||||
// The base validators are (currently) stored as strings
|
||||
let base_validators = self.base.networks.validators(network.into()).map(|v| {
|
||||
v.clone()
|
||||
.try_into()
|
||||
.expect("The hardcoded validators are assumed to be valid urls")
|
||||
});
|
||||
|
||||
self
|
||||
.base
|
||||
.fetched_validators
|
||||
.validators(network)
|
||||
.chain(self.network.validators(network))
|
||||
.chain(self.base.networks.validators(network.into()))
|
||||
.cloned()
|
||||
.chain(base_validators)
|
||||
}
|
||||
|
||||
pub fn get_validators_with_api_endpoint(
|
||||
&self,
|
||||
network: WalletNetwork,
|
||||
) -> impl Iterator<Item = ValidatorWithApiEndpoint> + '_ {
|
||||
) -> impl Iterator<Item = ValidatorUrlWithApiEndpoint> + '_ {
|
||||
self
|
||||
.get_validators(network)
|
||||
.filter_map(|validator| ValidatorWithApiEndpoint::try_from(validator.clone()).ok())
|
||||
.into_iter()
|
||||
.filter_map(|validator| ValidatorUrlWithApiEndpoint::try_from(validator).ok())
|
||||
}
|
||||
|
||||
pub fn get_mixnet_contract_address(&self, network: WalletNetwork) -> Option<cosmrs::AccountId> {
|
||||
@@ -169,13 +175,13 @@ impl Config {
|
||||
pub async fn check_validator_health(
|
||||
&self,
|
||||
network: WalletNetwork,
|
||||
) -> Result<Vec<(ValidatorDetails, StatusCode)>, BackendError> {
|
||||
) -> Result<Vec<(ValidatorUrl, StatusCode)>, BackendError> {
|
||||
// Limit the number of validators we query
|
||||
let max_validators = 200_usize;
|
||||
let validators_to_query = || self.get_validators(network).take(max_validators).cloned();
|
||||
let validators_to_query = || self.get_validators(network).take(max_validators);
|
||||
|
||||
let validator_urls = validators_to_query().map(|v| {
|
||||
let mut health_url = v.nymd_url();
|
||||
let mut health_url = v.nymd_url.clone();
|
||||
health_url.set_path("health");
|
||||
(v, health_url)
|
||||
});
|
||||
@@ -199,7 +205,7 @@ impl Config {
|
||||
#[allow(unused)]
|
||||
pub async fn check_validator_health_for_all_networks(
|
||||
&self,
|
||||
) -> Result<HashMap<WalletNetwork, Vec<(ValidatorDetails, StatusCode)>>, BackendError> {
|
||||
) -> Result<HashMap<WalletNetwork, Vec<(ValidatorUrl, StatusCode)>>, BackendError> {
|
||||
let validator_health_requests =
|
||||
WalletNetwork::iter().map(|network| self.check_validator_health(network));
|
||||
|
||||
@@ -217,21 +223,39 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike `ValidatorDetails` this represents validators which are always supposed to have a
|
||||
// validator-api endpoint running.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct ValidatorUrl {
|
||||
pub nymd_url: Url,
|
||||
pub api_url: Option<Url>,
|
||||
}
|
||||
|
||||
impl TryFrom<ValidatorDetails> for ValidatorUrl {
|
||||
type Error = BackendError;
|
||||
|
||||
fn try_from(validator: ValidatorDetails) -> Result<Self, Self::Error> {
|
||||
Ok(ValidatorUrl {
|
||||
nymd_url: validator.nymd_url.parse()?,
|
||||
api_url: match &validator.api_url {
|
||||
Some(url) => Some(url.parse()?),
|
||||
None => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ValidatorWithApiEndpoint {
|
||||
pub struct ValidatorUrlWithApiEndpoint {
|
||||
pub nymd_url: Url,
|
||||
pub api_url: Url,
|
||||
}
|
||||
|
||||
impl TryFrom<ValidatorDetails> for ValidatorWithApiEndpoint {
|
||||
impl TryFrom<ValidatorUrl> for ValidatorUrlWithApiEndpoint {
|
||||
type Error = BackendError;
|
||||
|
||||
fn try_from(validator: ValidatorDetails) -> Result<Self, Self::Error> {
|
||||
match validator.api_url() {
|
||||
Some(api_url) => Ok(ValidatorWithApiEndpoint {
|
||||
nymd_url: validator.nymd_url(),
|
||||
fn try_from(validator: ValidatorUrl) -> Result<Self, Self::Error> {
|
||||
match validator.api_url {
|
||||
Some(api_url) => Ok(ValidatorUrlWithApiEndpoint {
|
||||
nymd_url: validator.nymd_url,
|
||||
api_url,
|
||||
}),
|
||||
None => Err(BackendError::NoValidatorApiUrlConfigured),
|
||||
@@ -244,13 +268,13 @@ impl TryFrom<ValidatorDetails> for ValidatorWithApiEndpoint {
|
||||
struct OptionalValidators {
|
||||
// User supplied additional validator urls in addition to the hardcoded ones.
|
||||
// These are separate fields, rather than a map, to force the serialization order.
|
||||
mainnet: Option<Vec<ValidatorDetails>>,
|
||||
sandbox: Option<Vec<ValidatorDetails>>,
|
||||
qa: Option<Vec<ValidatorDetails>>,
|
||||
mainnet: Option<Vec<ValidatorUrl>>,
|
||||
sandbox: Option<Vec<ValidatorUrl>>,
|
||||
qa: Option<Vec<ValidatorUrl>>,
|
||||
}
|
||||
|
||||
impl OptionalValidators {
|
||||
fn validators(&self, network: WalletNetwork) -> impl Iterator<Item = &ValidatorDetails> {
|
||||
fn validators(&self, network: WalletNetwork) -> impl Iterator<Item = &ValidatorUrl> {
|
||||
match network {
|
||||
WalletNetwork::MAINNET => self.mainnet.as_ref(),
|
||||
WalletNetwork::SANDBOX => self.sandbox.as_ref(),
|
||||
@@ -273,15 +297,17 @@ mod tests {
|
||||
ValidatorDetails {
|
||||
nymd_url: "https://foo".to_string(),
|
||||
api_url: None,
|
||||
},
|
||||
ValidatorDetails {
|
||||
nymd_url: "https://baz".to_string(),
|
||||
api_url: Some("https://baz/api".to_string()),
|
||||
}
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
ValidatorUrl {
|
||||
nymd_url: "https://baz".parse().unwrap(),
|
||||
api_url: Some("https://baz/api".parse().unwrap()),
|
||||
},
|
||||
]),
|
||||
sandbox: Some(vec![ValidatorDetails {
|
||||
nymd_url: "https://bar".to_string(),
|
||||
api_url: Some("https://bar/api".to_string()),
|
||||
sandbox: Some(vec![ValidatorUrl {
|
||||
nymd_url: "https://bar".parse().unwrap(),
|
||||
api_url: Some("https://bar/api".parse().unwrap()),
|
||||
}]),
|
||||
qa: None,
|
||||
},
|
||||
@@ -293,14 +319,14 @@ mod tests {
|
||||
assert_eq!(
|
||||
toml::to_string_pretty(&test_config()).unwrap(),
|
||||
r#"[[network.mainnet]]
|
||||
nymd_url = 'https://foo'
|
||||
nymd_url = 'https://foo/'
|
||||
|
||||
[[network.mainnet]]
|
||||
nymd_url = 'https://baz'
|
||||
nymd_url = 'https://baz/'
|
||||
api_url = 'https://baz/api'
|
||||
|
||||
[[network.sandbox]]
|
||||
nymd_url = 'https://bar'
|
||||
nymd_url = 'https://bar/'
|
||||
api_url = 'https://bar/api'
|
||||
"#
|
||||
);
|
||||
@@ -320,15 +346,15 @@ api_url = 'https://bar/api'
|
||||
let nymd_url = config
|
||||
.get_validators(WalletNetwork::MAINNET)
|
||||
.next()
|
||||
.map(ValidatorDetails::nymd_url)
|
||||
.map(|v| v.nymd_url)
|
||||
.unwrap();
|
||||
assert_eq!(nymd_url.to_string(), "https://foo/".to_string());
|
||||
assert_eq!(nymd_url.as_ref(), "https://foo/");
|
||||
|
||||
// The first entry is missing an API URL
|
||||
let api_url = config
|
||||
.get_validators(WalletNetwork::MAINNET)
|
||||
.next()
|
||||
.and_then(ValidatorDetails::api_url);
|
||||
.and_then(|v| v.api_url);
|
||||
assert_eq!(api_url, None);
|
||||
}
|
||||
|
||||
@@ -339,21 +365,15 @@ api_url = 'https://bar/api'
|
||||
let nymd_url = config
|
||||
.get_validators(WalletNetwork::MAINNET)
|
||||
.next()
|
||||
.map(ValidatorDetails::nymd_url)
|
||||
.map(|v| v.nymd_url)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
nymd_url.to_string(),
|
||||
"https://rpc.nyx.nodes.guru/".to_string()
|
||||
);
|
||||
assert_eq!(nymd_url.as_ref(), "https://rpc.nyx.nodes.guru/");
|
||||
|
||||
let api_url = config
|
||||
.get_validators(WalletNetwork::MAINNET)
|
||||
.next()
|
||||
.and_then(ValidatorDetails::api_url)
|
||||
.and_then(|v| v.api_url)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
api_url.to_string(),
|
||||
"https://api.nyx.nodes.guru/".to_string()
|
||||
);
|
||||
assert_eq!(api_url.as_ref(), "https://api.nyx.nodes.guru/",);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::coin::{Coin, Denom};
|
||||
use crate::config::{Config, ValidatorWithApiEndpoint};
|
||||
use crate::config::{Config, ValidatorUrlWithApiEndpoint};
|
||||
use crate::error::BackendError;
|
||||
use crate::network::Network;
|
||||
use crate::nymd_client;
|
||||
@@ -181,7 +181,7 @@ async fn _connect_with_mnemonic(
|
||||
}
|
||||
|
||||
fn create_clients(
|
||||
validators: &HashMap<Network, ValidatorWithApiEndpoint>,
|
||||
validators: &HashMap<Network, ValidatorUrlWithApiEndpoint>,
|
||||
mnemonic: &Mnemonic,
|
||||
config: &Config,
|
||||
) -> Result<Vec<Client<SigningNymdClient>>, BackendError> {
|
||||
@@ -206,7 +206,7 @@ fn create_clients(
|
||||
async fn choose_validators(
|
||||
mnemonic: Mnemonic,
|
||||
state: &tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<HashMap<Network, ValidatorWithApiEndpoint>, BackendError> {
|
||||
) -> Result<HashMap<Network, ValidatorUrlWithApiEndpoint>, BackendError> {
|
||||
let config = state.read().await.config();
|
||||
|
||||
// Try to connect to validators on all networks
|
||||
@@ -236,7 +236,7 @@ async fn choose_validators(
|
||||
async fn select_responding_validators(
|
||||
config: &Config,
|
||||
mnemonic: &Mnemonic,
|
||||
) -> Result<HashMap<Network, ValidatorWithApiEndpoint>, BackendError> {
|
||||
) -> Result<HashMap<Network, ValidatorUrlWithApiEndpoint>, BackendError> {
|
||||
use tokio::time::timeout;
|
||||
let validators = futures::future::join_all(Network::iter().map(|network| {
|
||||
timeout(
|
||||
@@ -264,11 +264,11 @@ async fn select_responding_validators(
|
||||
}
|
||||
|
||||
async fn try_connect_to_validators(
|
||||
validators: impl Iterator<Item = ValidatorWithApiEndpoint>,
|
||||
validators: impl Iterator<Item = ValidatorUrlWithApiEndpoint>,
|
||||
config: &Config,
|
||||
network: Network,
|
||||
mnemonic: Mnemonic,
|
||||
) -> Result<Option<(Network, ValidatorWithApiEndpoint)>, BackendError> {
|
||||
) -> Result<Option<(Network, ValidatorUrlWithApiEndpoint)>, BackendError> {
|
||||
for validator in validators {
|
||||
if let Some(responding_validator) =
|
||||
try_connect_to_validator(&validator, config, network, mnemonic.clone()).await?
|
||||
@@ -281,11 +281,11 @@ async fn try_connect_to_validators(
|
||||
}
|
||||
|
||||
async fn try_connect_to_validator(
|
||||
validator: &ValidatorWithApiEndpoint,
|
||||
validator: &ValidatorUrlWithApiEndpoint,
|
||||
config: &Config,
|
||||
network: Network,
|
||||
mnemonic: Mnemonic,
|
||||
) -> Result<Option<(Network, ValidatorWithApiEndpoint)>, BackendError> {
|
||||
) -> Result<Option<(Network, ValidatorUrlWithApiEndpoint)>, BackendError> {
|
||||
let client = validator_client::Client::new_signing(
|
||||
validator_client::Config::new(
|
||||
network.into(),
|
||||
|
||||
Reference in New Issue
Block a user