Skip to content

Commit

Permalink
Merge #1376
Browse files Browse the repository at this point in the history
1376: Loadtest: add a scenario for stressing fee ticker r=popzxc a=alekseysidorov



Co-authored-by: Aleksei Sidorov <[email protected]>
Co-authored-by: Aleksey Sidorov <[email protected]>
  • Loading branch information
3 people authored Feb 15, 2021
2 parents 7875fd7 + 58e4a76 commit 7bac7c5
Show file tree
Hide file tree
Showing 22 changed files with 812 additions and 269 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions changelog/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ All notable changes to the core components will be documented in this file.

### Changed

- The token name is now set for each scenario separately instead of the network section of the loadtest configuration.
- Rejected transactions are now stored in the database for 2 weeks only.

### Added

- Added a stressing dev fee ticker scenario to the loadtest.
- Added a `--sloppy` mode to the `dev-fee-ticker-server` to simulate bad networks with the random delays and fails.

### Fixed

## Release 2021-02-02
Expand Down
1 change: 1 addition & 0 deletions core/bin/zksync_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ chrono = { version = "0.4", features = ["serde", "rustc-serialize"] }
ctrlc = { version = "3.1", features = ["termination"] }
anyhow = "1.0"
thiserror = "1.0"
structopt = "0.3"
# TODO: should be removed after json rpc deps are updated is updated, current version (14.0) (ZKS-98).
futures01 = { package = "futures", version = "0.1" }
reqwest = { version = "0.10", features = ["blocking", "json"] }
Expand Down
104 changes: 86 additions & 18 deletions core/bin/zksync_api/src/bin/dev-ticker-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,45 @@ use bigdecimal::BigDecimal;
use chrono::{SecondsFormat, Utc};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::convert::TryFrom;
use std::{convert::TryFrom, time::Duration};
use structopt::StructOpt;
use zksync_crypto::rand::{thread_rng, Rng};

#[derive(Debug, Serialize, Deserialize)]
struct CoinMarketCapTokenQuery {
symbol: String,
}

macro_rules! make_sloppy {
($f: ident) => {{
|query| async {
if thread_rng().gen_range(0, 100) < 5 {
vlog::debug!("`{}` has been errored", stringify!($f));
return Ok(HttpResponse::InternalServerError().finish());
}

let duration = match thread_rng().gen_range(0, 100) {
0..=59 => Duration::from_millis(100),
60..=69 => Duration::from_secs(5),
_ => {
let ms = thread_rng().gen_range(100, 1000);
Duration::from_millis(ms)
}
};

vlog::debug!(
"`{}` has been delayed for {}ms",
stringify!($f),
duration.as_millis()
);
tokio::time::delay_for(duration).await;

let resp = $f(query).await;
resp
}
}};
}

async fn handle_coinmarketcap_token_price_query(
query: web::Query<CoinMarketCapTokenQuery>,
) -> Result<HttpResponse> {
Expand Down Expand Up @@ -84,31 +115,68 @@ async fn handle_coingecko_token_price_query(req: HttpRequest) -> Result<HttpResp
Ok(HttpResponse::Ok().json(resp))
}

fn main_scope(sloppy_mode: bool) -> actix_web::Scope {
if sloppy_mode {
web::scope("/")
.route(
"/cryptocurrency/quotes/latest",
web::get().to(make_sloppy!(handle_coinmarketcap_token_price_query)),
)
.route(
"/api/v3/coins/list",
web::get().to(make_sloppy!(handle_coingecko_token_list)),
)
.route(
"/api/v3/coins/{coin_id}/market_chart",
web::get().to(make_sloppy!(handle_coingecko_token_price_query)),
)
} else {
web::scope("/")
.route(
"/cryptocurrency/quotes/latest",
web::get().to(handle_coinmarketcap_token_price_query),
)
.route(
"/api/v3/coins/list",
web::get().to(handle_coingecko_token_list),
)
.route(
"/api/v3/coins/{coin_id}/market_chart",
web::get().to(handle_coingecko_token_price_query),
)
}
}

/// Ticker implementation for dev environment
///
/// Implements coinmarketcap API for tokens deployed using `deploy-dev-erc20`
/// Prices are randomly distributed around base values estimated from real world prices.
#[derive(Debug, StructOpt, Clone, Copy)]
struct FeeTickerOpts {
/// Activate "sloppy" mode.
///
/// With the option, server will provide a random delay for requests
/// (60% of 0.1 delay, 30% of 0.1 - 1.0 delay, 10% of 5 seconds delay),
/// and will randomly return errors for 5% of requests.
#[structopt(long)]
sloppy: bool,
}

fn main() {
vlog::init();

let mut runtime = actix_rt::System::new("dev-ticker");
let opts = FeeTickerOpts::from_args();
if opts.sloppy {
vlog::info!("Fee ticker server will run in a sloppy mode.");
}

runtime.block_on(async {
let mut runtime = actix_rt::System::new("dev-ticker");
runtime.block_on(async move {
HttpServer::new(move || {
App::new()
.wrap(middleware::Logger::default())
.wrap(Cors::new().send_wildcard().max_age(3600).finish())
.service(
web::scope("/")
.route(
"/cryptocurrency/quotes/latest",
web::get().to(handle_coinmarketcap_token_price_query),
)
.route(
"/api/v3/coins/list",
web::get().to(handle_coingecko_token_list),
)
.route(
"/api/v3/coins/{coin_id}/market_chart",
web::get().to(handle_coingecko_token_price_query),
),
)
.service(main_scope(opts.sloppy))
})
.bind("0.0.0.0:9876")
.unwrap()
Expand Down
6 changes: 6 additions & 0 deletions core/lib/types/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ impl From<&str> for TokenLike {
}
}

impl From<&TokenLike> for TokenLike {
fn from(inner: &TokenLike) -> Self {
inner.to_owned()
}
}

impl fmt::Display for TokenLike {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand Down
8 changes: 5 additions & 3 deletions core/tests/loadtest/config/localhost.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
[main_wallet]
address = '0x36615cf349d7f6344891b1e7ca7c72883f5dc049'
private_key = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'
# The name of the token used for testing.
token_name = 'ETH'

[network]
# Network kind used for testing.
name = 'localhost'
# Fee for the Ethereum transactions in gwei.
eth_fee = 10000000000
# Fee for the zkSync transactions in gwei.
zksync_fee = 100000000
zksync_fee = 10000000000

# A list of scenarios used in parallel in this loadtest.
[[scenarios]]
name = 'transfer'
token_name = 'ETH'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
# Amount of iterations to rotate funds, "length" of the test.
Expand All @@ -25,18 +24,21 @@ wallets_amount = 400

[[scenarios]]
name = "withdraw"
token_name = 'GNT'
# Amount of intermediate wallets to use.
wallets_amount = 15
# Amount of "withdraw and deposit" iterations.
withdraw_rounds = 4

[[scenarios]]
name = "full_exit"
token_name = 'ETH'
# Amount of intermediate wallets to use.
wallets_amount = 10

[[scenarios]]
name = 'batch_transfers'
token_name = 'DAI'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
# Amount of iterations to rotate funds, "length" of the test.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
[main_wallet]
address = '0x36615cf349d7f6344891b1e7ca7c72883f5dc049'
private_key = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'
# The name of the token used for testing.
token_name = "DAI"

[network]
# Network kind used for testing.
Expand All @@ -14,31 +12,39 @@ eth_fee = 10000000000
zksync_fee = 100000000000

[[scenarios]]
name = 'transfer'
name = 'fee_ticker'
# The name of the token used for testing.
token_name = 'BAT'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
transfer_rounds = 50
wallets_amount = 400
transfer_rounds = 10
wallets_amount = 40
max_batch_size = 15

[[scenarios]]
name = "withdraw"
wallets_amount = 15
withdraw_rounds = 4
name = 'fee_ticker'
# The name of the token used for testing.
token_name = 'ETH'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
transfer_rounds = 10
wallets_amount = 40

[[scenarios]]
name = "full_exit"
wallets_amount = 10
name = 'fee_ticker'
# The name of the token used for testing.
token_name = 'DAI'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
transfer_rounds = 10
wallets_amount = 40
max_batch_size = 15

[[scenarios]]
name = 'batch_transfers'
name = 'fee_ticker'
# The name of the token used for testing.
token_name = 'tGLM'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
# Amount of iterations to rotate funds, "length" of the test.
transfer_rounds = 50
# Amount of intermediate wallets to use.
wallets_amount = 100
# Maximum transactions batch size.
#
# The test uses the following batch sizes:
# [2, max_batch_size / 2, max_batch_size]
max_batch_size = 15
transfer_rounds = 10
wallets_amount = 40
6 changes: 4 additions & 2 deletions core/tests/loadtest/config/localhost_lite.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
[main_wallet]
address = '0x36615cf349d7f6344891b1e7ca7c72883f5dc049'
private_key = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'
# The name of the token used for testing.
token_name = 'DAI'

[network]
# Network kind used for testing.
Expand All @@ -15,22 +13,26 @@ zksync_fee = 100000000000

[[scenarios]]
name = 'transfer'
token_name = 'GNT'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
transfer_rounds = 2
wallets_amount = 20

[[scenarios]]
name = "withdraw"
token_name = 'ETH'
wallets_amount = 15
withdraw_rounds = 1

[[scenarios]]
token_name = 'BAT'
name = "full_exit"
wallets_amount = 10

[[scenarios]]
name = 'batch_transfers'
token_name = 'DAI'
# Amount of money to be used in the transfer, in gwei.
transfer_size = 1
transfer_rounds = 10
Expand Down
4 changes: 1 addition & 3 deletions core/tests/loadtest/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use web3::types::H256;
// Workspace uses
use zksync::Network;
use zksync_types::{Address, TokenLike};
use zksync_types::Address;
// Local uses
use crate::scenarios::ScenarioConfig;

Expand All @@ -23,8 +23,6 @@ use crate::scenarios::ScenarioConfig;
pub struct AccountInfo {
pub address: Address,
pub private_key: H256,
/// The name of the token used for testing.
pub token_name: TokenLike,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
Expand Down
Loading

0 comments on commit 7bac7c5

Please sign in to comment.