Skip to content

Commit

Permalink
Remove reqwest::blocking usage from fee ticker
Browse files Browse the repository at this point in the history
  • Loading branch information
popzxc committed Mar 4, 2022
1 parent 38973d3 commit 62a789e
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 190 deletions.
2 changes: 1 addition & 1 deletion core/bin/zksync_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ ctrlc = { version = "3.1", features = ["termination"] }
anyhow = "1.0"
thiserror = "1.0"
structopt = "0.3"
reqwest = { version = "0.11", features = ["blocking", "json"] }
reqwest = { version = "0.11", features = ["json"] }
tiny-keccak = "1.4.2"
async-trait = "0.1"
jsonwebtoken = "7"
Expand Down
8 changes: 5 additions & 3 deletions core/bin/zksync_api/src/fee_ticker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,15 @@ pub fn run_updaters(
tokio::spawn(ticker_api.keep_price_updated())
}

TokenPriceSource::CoinGecko => {
TokenPriceSource::CoinGecko => tokio::spawn(async move {
let token_price_api =
CoinGeckoAPI::new(client, base_url.parse().expect("Correct CoinGecko url"))
.await
.expect("failed to init CoinGecko client");
let ticker_api = TickerApi::new(db_pool, token_price_api);
tokio::spawn(ticker_api.keep_price_updated())
}

ticker_api.keep_price_updated().await;
}),
};
tasks.push(price_updater);
tasks
Expand Down
162 changes: 2 additions & 160 deletions core/bin/zksync_api/src/fee_ticker/tests.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
use std::any::Any;

use actix_web::{web, App, HttpResponse, HttpServer};

use async_trait::async_trait;
use bigdecimal::BigDecimal;
use chrono::Utc;
use futures::executor::block_on;
use futures::future::{AbortHandle, Abortable};
use std::str::FromStr;
use std::thread::sleep;
use tokio::time::Duration;
use zksync_types::{Address, Token, TokenId, TokenKind, TokenPrice};
use zksync_utils::{
big_decimal_to_ratio, ratio_to_big_decimal, ratio_to_scaled_u64, scaled_u64_to_ratio,
UnsignedRatioSerializeAsDecimal,
ratio_to_big_decimal, ratio_to_scaled_u64, scaled_u64_to_ratio, UnsignedRatioSerializeAsDecimal,
};

use crate::fee_ticker::{
ticker_api::{
coingecko::{CoinGeckoTokenInfo, CoinGeckoTokenList},
TokenPriceAPI,
},
ticker_api::TokenPriceAPI,
validator::{cache::TokenInMemoryCache, FeeTokenValidator},
};

Expand Down Expand Up @@ -222,48 +213,6 @@ impl TokenPriceAPI for ErrorTickerApi {
}
}

fn run_server(token_address: Address) -> (String, AbortHandle) {
let mut url = None;
let mut server = None;
for i in 9000..9999 {
let new_url = format!("127.0.0.1:{}", i);
// Try to bind to some port, hope that 999 variants will be enough
if let Ok(ser) = HttpServer::new(move || {
App::new()
.service(
web::resource("/api/v3/coins/DAI/market_chart").route(web::get().to(|| {
sleep(Duration::from_secs(100));
HttpResponse::MethodNotAllowed()
})),
)
.service(web::resource("/api/v3/coins/list").to(move || {
let mut platforms = HashMap::new();
platforms.insert(
String::from("ethereum"),
serde_json::Value::String(serde_json::to_string(&token_address).unwrap()),
);
HttpResponse::Ok().json(CoinGeckoTokenList(vec![CoinGeckoTokenInfo {
id: "dai".to_string(),
platforms,
}]))
}))
})
.bind(new_url.clone())
{
server = Some(ser);
url = Some(new_url);
break;
}
}

let server = server.expect("Could not bind to port from 9000 to 9999");
let (abort_handle, abort_registration) = AbortHandle::new_pair();
let future = Abortable::new(server.run(), abort_registration);
tokio::spawn(future);
let address = format!("http://{}/", &url.unwrap());
(address, abort_handle)
}

fn get_normal_and_subsidy_fee(
ticker: &mut FeeTicker,
tx_type: TxFeeTypes,
Expand Down Expand Up @@ -759,110 +708,3 @@ fn test_zero_price_token_fee() {
))
.unwrap_err();
}

#[actix_rt::test]
#[ignore]
// It's ignore because we can't initialize coingecko in current way with block
async fn test_error_coingecko_api() {
let token = Token {
id: TokenId(1),
address: Address::random(),
symbol: String::from("DAI"),
decimals: 18,
kind: TokenKind::ERC20,
is_nft: false,
};
let (address, handler) = run_server(token.address);
let client = reqwest::ClientBuilder::new()
.timeout(CONNECTION_TIMEOUT)
.connect_timeout(CONNECTION_TIMEOUT)
.build()
.expect("Failed to build reqwest::Client");
let coingecko = CoinGeckoAPI::new(client, address.parse().unwrap()).unwrap();
let validator = FeeTokenValidator::new(
TokenInMemoryCache::new(),
chrono::Duration::seconds(100),
BigDecimal::from(100),
Default::default(),
);
let connection_pool = ConnectionPool::new(Some(1));
{
let mut storage = connection_pool.access_storage().await.unwrap();
storage
.tokens_schema()
.store_token(token.clone())
.await
.unwrap();
storage
.tokens_schema()
.update_historical_ticker_price(
token.id,
TokenPrice {
usd_price: big_decimal_to_ratio(&BigDecimal::from(10)).unwrap(),
last_updated: chrono::offset::Utc::now(),
},
)
.await
.unwrap();
}
let _ticker_api = TickerApi::new(connection_pool, coingecko);

let config = get_test_ticker_config();
let ticker = FeeTicker::new(Box::new(MockTickerInfo::default()), config, validator);
for _ in 0..1000 {
ticker
.get_fee_from_ticker_in_wei(
TxFeeTypes::FastWithdraw,
token.id.into(),
Address::default(),
)
.await
.unwrap();
ticker
.get_token_price(token.id.into(), TokenPriceRequestType::USDForOneWei)
.await
.unwrap();
}
handler.abort();
}

#[tokio::test]
#[ignore]
async fn test_error_api() {
let validator = FeeTokenValidator::new(
TokenInMemoryCache::new(),
chrono::Duration::seconds(100),
BigDecimal::from(100),
Default::default(),
);
let connection_pool = ConnectionPool::new(Some(1));
connection_pool
.access_storage()
.await
.unwrap()
.tokens_schema()
.update_historical_ticker_price(
TokenId(1),
TokenPrice {
usd_price: big_decimal_to_ratio(&BigDecimal::from(10)).unwrap(),
last_updated: chrono::offset::Utc::now(),
},
)
.await
.unwrap();
let config = get_test_ticker_config();
let ticker = FeeTicker::new(Box::new(MockTickerInfo::default()), config, validator);

ticker
.get_fee_from_ticker_in_wei(
TxFeeTypes::FastWithdraw,
TokenId(1).into(),
Address::default(),
)
.await
.unwrap();
ticker
.get_token_price(TokenId(1).into(), TokenPriceRequestType::USDForOneWei)
.await
.unwrap();
}
10 changes: 6 additions & 4 deletions core/bin/zksync_api/src/fee_ticker/ticker_api/coingecko.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ pub struct CoinGeckoAPI {
}

impl CoinGeckoAPI {
pub fn new(client: reqwest::Client, base_url: Url) -> anyhow::Result<Self> {
pub async fn new(client: reqwest::Client, base_url: Url) -> anyhow::Result<Self> {
let token_list_url = base_url
.join("api/v3/coins/list?include_platform=true")
.expect("failed to join URL path");

let token_list = reqwest::blocking::get(token_list_url)
let token_list = reqwest::get(token_list_url)
.await
.map_err(|err| anyhow::format_err!("CoinGecko API request failed: {}", err))?
.json::<CoinGeckoTokenList>()?;
.json::<CoinGeckoTokenList>()
.await?;

let mut token_ids = HashMap::new();
for token in token_list.0 {
Expand Down Expand Up @@ -160,7 +162,7 @@ mod tests {
async fn test_coingecko_api() {
let ticker_url = parse_env("FEE_TICKER_COINGECKO_BASE_URL");
let client = reqwest::Client::new();
let api = CoinGeckoAPI::new(client, ticker_url).unwrap();
let api = CoinGeckoAPI::new(client, ticker_url).await.unwrap();
let token = Token::new(TokenId(0), Default::default(), "ETH", 18, TokenKind::ERC20);
api.get_price(&token)
.await
Expand Down
17 changes: 0 additions & 17 deletions core/bin/zksync_api/src/fee_ticker/validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,6 @@ impl FeeTokenValidator {
mod tests {
use super::*;
use crate::fee_ticker::validator::cache::TokenInMemoryCache;
use crate::fee_ticker::validator::watcher::UniswapTokenWatcher;
use bigdecimal::Zero;
use num::rational::Ratio;
use num::BigUint;
use std::collections::HashMap;
Expand All @@ -190,21 +188,6 @@ mod tests {
}
}

#[tokio::test]
#[ignore]
// We can use this test only online, run it manually if you need to test connection to uniswap
async fn get_real_token_amount() {
let mut watcher = UniswapTokenWatcher::new(
"https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2".to_string(),
);
let dai_token_address =
Address::from_str("6b175474e89094c44da98b954eedeac495271d0f").unwrap();
let dai_token = Token::new(TokenId(1), dai_token_address, "DAI", 18, TokenKind::ERC20);

let amount = watcher.get_token_market_volume(&dai_token).await.unwrap();
assert!(amount > BigDecimal::zero());
}

#[tokio::test]
async fn check_tokens() {
let dai_token_address =
Expand Down
10 changes: 5 additions & 5 deletions core/lib/config/src/configs/ticker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ impl TickerConfig {
}

/// Returns the token price source type and the corresponding API URL.
pub fn price_source(&self) -> (TokenPriceSource, &str) {
pub fn price_source(&self) -> (TokenPriceSource, String) {
let url = match self.token_price_source {
TokenPriceSource::CoinGecko => self.coingecko_base_url.as_ref(),
TokenPriceSource::CoinMarketCap => self.coinmarketcap_base_url.as_ref(),
TokenPriceSource::CoinGecko => self.coingecko_base_url.clone(),
TokenPriceSource::CoinMarketCap => self.coinmarketcap_base_url.clone(),
};
(self.token_price_source, url)
}
Expand Down Expand Up @@ -120,13 +120,13 @@ FEE_TICKER_SUBSIDY_CPK_PRICE_USD_SCALED=100
config.token_price_source = TokenPriceSource::CoinGecko;
assert_eq!(
config.price_source(),
(TokenPriceSource::CoinGecko, COINGECKO_URL)
(TokenPriceSource::CoinGecko, COINGECKO_URL.into())
);

config.token_price_source = TokenPriceSource::CoinMarketCap;
assert_eq!(
config.price_source(),
(TokenPriceSource::CoinMarketCap, COINMARKETCAP_URL)
(TokenPriceSource::CoinMarketCap, COINMARKETCAP_URL.into())
);
}
}

0 comments on commit 62a789e

Please sign in to comment.