Skip to content

Commit

Permalink
Merge branch 'dev' into breaking
Browse files Browse the repository at this point in the history
  • Loading branch information
Deniallugo committed Jul 13, 2021
2 parents 5dd87c5 + b2f056a commit dfee9cc
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 476 deletions.
17 changes: 3 additions & 14 deletions core/bin/zksync_api/src/api_server/rest/v02/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use actix_web::{web, App, Scope};
use bigdecimal::BigDecimal;
use chrono::Utc;
use futures::{channel::mpsc, StreamExt};
use num::{rational::Ratio, BigUint};
use num::BigUint;
use once_cell::sync::Lazy;
use serde::de::DeserializeOwned;
use tokio::sync::Mutex;
Expand Down Expand Up @@ -792,13 +792,7 @@ pub fn dummy_fee_ticker(prices: &[(TokenLike, BigDecimal)]) -> mpsc::Sender<Tick
1_u64.into(),
);

let subsidy_fee = normal_fee.clone();

let res = Ok(ResponseFee {
normal_fee,
subsidy_fee,
subsidy_size_usd: Ratio::from_integer(0u32.into()),
});
let res = Ok(ResponseFee { normal_fee });

response.send(res).expect("Unable to send response");
}
Expand Down Expand Up @@ -831,13 +825,8 @@ pub fn dummy_fee_ticker(prices: &[(TokenLike, BigDecimal)]) -> mpsc::Sender<Tick
BigUint::from(transactions.len()).into(),
BigUint::from(transactions.len()).into(),
);
let subsidy_fee = normal_fee.clone();

let res = Ok(ResponseBatchFee {
normal_fee,
subsidy_fee,
subsidy_size_usd: Ratio::from_integer(0u32.into()),
});
let res = Ok(ResponseBatchFee { normal_fee });

response.send(res).expect("Unable to send response");
}
Expand Down
26 changes: 2 additions & 24 deletions core/bin/zksync_api/src/api_server/rpc_server/rpc_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,8 @@ impl RpcApp {
let result =
Self::ticker_request(ticker.clone(), tx_type.into(), address, token.clone()).await?;

let token = self.tx_sender.token_info_from_id(token).await?;
let allowed_subsidy = self
.tx_sender
.subsidy_accumulator
.get_allowed_subsidy(&token.address);
let fee = if allowed_subsidy >= result.subsidy_size_usd {
result.subsidy_fee
} else {
result.normal_fee
};

metrics::histogram!("api.rpc.get_tx_fee", start.elapsed());
Ok(fee)
Ok(result.normal_fee)
}

pub async fn _impl_get_txs_batch_fee_in_wei(
Expand Down Expand Up @@ -275,20 +264,9 @@ impl RpcApp {
.collect();
let result = Self::ticker_batch_fee_request(ticker, transactions, token.clone()).await?;

let token = self.tx_sender.token_info_from_id(token).await?;
let allowed_subsidy = self
.tx_sender
.subsidy_accumulator
.get_allowed_subsidy(&token.address);
let fee = if allowed_subsidy >= result.subsidy_size_usd {
result.subsidy_fee
} else {
result.normal_fee
};

metrics::histogram!("api.rpc.get_txs_batch_fee_in_wei", start.elapsed());
Ok(TotalFee {
total_fee: fee.total_fee,
total_fee: result.normal_fee.total_fee,
})
}

Expand Down
189 changes: 13 additions & 176 deletions core/bin/zksync_api/src/api_server/tx_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Built-in uses
use std::iter::FromIterator;
use std::sync::{Arc, RwLock};
use std::{
collections::{HashMap, HashSet},
fmt::Display,
Expand All @@ -11,13 +10,12 @@ use std::{

// External uses
use bigdecimal::BigDecimal;
use chrono::Utc;
use futures::{
channel::{mpsc, oneshot},
prelude::*,
};
use itertools::izip;
use num::{bigint::ToBigInt, rational::Ratio, BigUint, CheckedSub, Zero};
use num::{bigint::ToBigInt, BigUint, Zero};
use thiserror::Error;

// Workspace uses
Expand All @@ -34,7 +32,6 @@ use zksync_types::{
},
AccountId, Address, BatchFee, Fee, Token, TokenId, TokenLike, TxFeeTypes, ZkSyncTx, H160,
};
use zksync_utils::ratio_to_big_decimal;

// Local uses
use crate::{
Expand Down Expand Up @@ -65,75 +62,6 @@ pub struct TxSender {
// Limit the number of both transactions and Ethereum signatures per batch.
pub max_number_of_transactions_per_batch: usize,
pub max_number_of_authors_per_batch: usize,

pub subsidy_accumulator: SubsidyAccumulator,
}

/// Used to store paid subsidy and daily limit
#[derive(Debug)]
pub struct SubsidyAccumulator {
/// Subsidy limit for token address in USD (e.g. 1 -> 1 USD)
daily_limits: HashMap<Address, Ratio<BigUint>>,
/// Paid subsidy per token, dated by time when first subsidy is paid
#[allow(clippy::type_complexity)]
limit_used: Arc<RwLock<HashMap<Address, (Ratio<BigUint>, chrono::DateTime<Utc>)>>>,
}

impl Clone for SubsidyAccumulator {
fn clone(&self) -> Self {
Self {
daily_limits: self.daily_limits.clone(),
limit_used: Arc::clone(&self.limit_used),
}
}
}

impl SubsidyAccumulator {
pub fn new(daily_limits: HashMap<Address, Ratio<BigUint>>) -> Self {
Self {
daily_limits,
limit_used: Arc::new(RwLock::new(HashMap::new())),
}
}

pub fn get_allowed_subsidy(&self, token_address: &Address) -> Ratio<BigUint> {
let limit = self
.daily_limits
.get(token_address)
.cloned()
.unwrap_or_else(|| Ratio::from_integer(0u32.into()));
let used = self.limit_used.read().expect("subsidy counter rlock");
let subsidy_used = used
.get(token_address)
.map(|(subs, _)| subs.clone())
.unwrap_or_else(|| Ratio::from_integer(0u32.into()));
limit
.checked_sub(&subsidy_used)
.unwrap_or_else(|| Ratio::from_integer(0u32.into()))
}

pub fn get_total_paid_subsidy(&self, token_address: &Address) -> Ratio<BigUint> {
let used = self.limit_used.read().expect("subsidy counter rlock");
used.get(token_address)
.map(|(subs, _)| subs.clone())
.unwrap_or_else(|| Ratio::from_integer(0u32.into()))
}

pub fn add_used_subsidy(&self, token_address: &Address, subsidy_amount: Ratio<BigUint>) {
let mut used = self.limit_used.write().expect("subsidy counter wlock");
let new_value = if let Some((mut old_amount, creation_time)) = used.remove(token_address) {
if Utc::now().signed_duration_since(creation_time) >= chrono::Duration::days(1) {
(Ratio::from_integer(0u32.into()), Utc::now())
} else {
old_amount += subsidy_amount;
(old_amount, creation_time)
}
} else {
(Ratio::from_integer(0u32.into()), Utc::now())
};

used.insert(*token_address, new_value);
}
}

#[derive(Debug, Error)]
Expand Down Expand Up @@ -219,8 +147,6 @@ impl TxSender {
let max_number_of_authors_per_batch =
config.api.common.max_number_of_authors_per_batch as usize;

let subsidy_accumulator = SubsidyAccumulator::new(config.ticker.get_subsidy_limits());

Self {
core_api_client,
pool: connection_pool,
Expand All @@ -234,7 +160,6 @@ impl TxSender {
fee_free_accounts: HashSet::from_iter(config.api.common.fee_free_accounts.clone()),
max_number_of_transactions_per_batch,
max_number_of_authors_per_batch,
subsidy_accumulator,
}
}

Expand Down Expand Up @@ -362,8 +287,6 @@ impl TxSender {

// Resolve the token.
let token = self.token_info_from_id(tx.token_id()).await?;
let allowed_subsidy = self.subsidy_accumulator.get_allowed_subsidy(&token.address);
let mut paid_subsidy = Ratio::from_integer(0u32.into());
let msg_to_sign = tx
.get_ethereum_sign_message(token.clone())
.map(String::into_bytes);
Expand Down Expand Up @@ -406,24 +329,9 @@ impl TxSender {
.into();
let provided_fee: BigDecimal = provided_fee.to_bigint().unwrap().into();
// Scaling the fee required since the price may change between signing the transaction and sending it to the server.
let scaled_provided_fee = scale_user_fee_up(provided_fee.clone());
let scaled_provided_fee = scale_user_fee_up(provided_fee);
if required_fee >= scaled_provided_fee && should_enforce_fee {
let max_subsidy = required_fee_data.get_max_subsidy(&allowed_subsidy);

if max_subsidy >= &required_fee - &scaled_provided_fee {
paid_subsidy += required_fee_data.subsidy_size_usd
} else {
vlog::error!(
"User provided fee is too low, required: {}, provided: {} (scaled: {}); difference {}, token: {:?}",
required_fee.to_string(),
provided_fee.to_string(),
scaled_provided_fee.to_string(),
(&required_fee - &scaled_provided_fee).to_string(),
token
);

return Err(SubmitError::TxAdd(TxAddError::TxFeeTooLow));
}
return Err(SubmitError::TxAdd(TxAddError::TxFeeTooLow));
}
}

Expand Down Expand Up @@ -463,24 +371,6 @@ impl TxSender {
.map_err(SubmitError::communication_core_server)?
.map_err(SubmitError::TxAdd)?;
// if everything is OK, return the transactions hashes.
if paid_subsidy > Ratio::from_integer(0u32.into()) {
let paid_subsidy_dec = ratio_to_big_decimal(&paid_subsidy, 6).to_string();
let total_paid_subsidy = ratio_to_big_decimal(
&self
.subsidy_accumulator
.get_total_paid_subsidy(&token.address),
6,
);
vlog::info!(
"Paid subsidy for tx, tx: {}, token: {}, subsidy_tx: {} USD, subsidy_token_total: {} USD",
tx_hash.to_string(),
&token.address,
paid_subsidy_dec,
total_paid_subsidy
);
self.subsidy_accumulator
.add_used_subsidy(&token.address, paid_subsidy);
}
Ok(tx.hash())
}

Expand Down Expand Up @@ -566,7 +456,6 @@ impl TxSender {
}
}

let mut subsidy_paid = None;
// Only one token in batch
if token_fees.len() == 1 {
let (batch_token, fee_paid) = token_fees.into_iter().next().unwrap();
Expand All @@ -582,22 +471,13 @@ impl TxSender {
BigDecimal::from(batch_token_fee.normal_fee.total_fee.to_bigint().unwrap());

// Not enough fee
if required_normal_fee >= user_provided_fee {
let allowed_subsidy = self.subsidy_accumulator.get_allowed_subsidy(&batch_token);
let max_subsidy = batch_token_fee.get_max_subsidy(&allowed_subsidy);
let required_subsidy = &required_normal_fee - &user_provided_fee;
// check if subsidy can be used
if max_subsidy >= required_subsidy {
subsidy_paid = Some((batch_token, batch_token_fee.subsidy_size_usd));
} else {
vlog::error!(
"User provided batch fee in token is too low, required: {}, provided (scaled): {} (subsidy: {})",
required_normal_fee.to_string(),
user_provided_fee.to_string(),
max_subsidy.to_string(),
);
return Err(SubmitError::TxAdd(TxAddError::TxBatchFeeTooLow));
}
if required_normal_fee > user_provided_fee {
vlog::error!(
"User provided batch fee in token is too low, required: {}, provided (scaled): {}",
required_normal_fee.to_string(),
user_provided_fee.to_string(),
);
return Err(SubmitError::TxAdd(TxAddError::TxBatchFeeTooLow));
}
} else {
// Calculate required fee for ethereum token
Expand All @@ -622,7 +502,7 @@ impl TxSender {

// Scaling the fee required since the price may change between signing the transaction and sending it to the server.
let scaled_provided_fee_in_usd = scale_user_fee_up(provided_total_usd_fee.clone());
if required_total_usd_fee >= scaled_provided_fee_in_usd {
if required_total_usd_fee > scaled_provided_fee_in_usd {
vlog::error!(
"User provided batch fee is too low, required: {}, provided: {} (scaled: {}); difference {}",
&required_total_usd_fee,
Expand Down Expand Up @@ -706,25 +586,6 @@ impl TxSender {
}
verified_txs.extend(verified_batch.into_iter());

if let Some((subsidy_token, subsidy_paid)) = subsidy_paid {
let paid_subsidy_dec = ratio_to_big_decimal(&subsidy_paid, 6);
let total_paid_subsidy = ratio_to_big_decimal(
&self
.subsidy_accumulator
.get_total_paid_subsidy(&subsidy_token),
6,
);

vlog::info!(
"Paid subsidy for batch: token: {}, , subsidy_tx: {} USD, subsidy_token_total: {} USD",
subsidy_token,
paid_subsidy_dec,
total_paid_subsidy
);
self.subsidy_accumulator
.add_used_subsidy(&subsidy_token, subsidy_paid);
}

let tx_hashes: Vec<TxHash> = verified_txs.iter().map(|tx| tx.tx.hash()).collect();
// Send verified transactions to the mempool.
self.core_api_client
Expand Down Expand Up @@ -753,19 +614,7 @@ impl TxSender {
token.clone(),
)
.await?;

if resp_fee.subsidy_fee.total_fee == resp_fee.normal_fee.total_fee {
return Ok(resp_fee.normal_fee);
}

let token = self.token_info_from_id(token).await?;

let allowed_subsidy = self.subsidy_accumulator.get_allowed_subsidy(&token.address);
if allowed_subsidy >= resp_fee.subsidy_size_usd {
Ok(resp_fee.subsidy_fee)
} else {
Ok(resp_fee.normal_fee)
}
Ok(resp_fee.normal_fee)
}

pub async fn get_txs_batch_fee_in_wei(
Expand All @@ -779,19 +628,7 @@ impl TxSender {
token.clone(),
)
.await?;

if resp_fee.normal_fee.total_fee == resp_fee.subsidy_fee.total_fee {
return Ok(resp_fee.normal_fee);
}

let token = self.token_info_from_id(token).await?;

let allowed_subsidy = self.subsidy_accumulator.get_allowed_subsidy(&token.address);
if allowed_subsidy >= resp_fee.subsidy_size_usd {
Ok(resp_fee.subsidy_fee)
} else {
Ok(resp_fee.normal_fee)
}
Ok(resp_fee.normal_fee)
}

/// For forced exits, we must check that target account exists for more
Expand Down
14 changes: 0 additions & 14 deletions core/bin/zksync_api/src/fee_ticker/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,3 @@ pub(crate) const BASE_MINT_NFT_COST: u64 = VerifyCost::MINT_NFT_COST
pub(crate) const BASE_SWAP_COST: u64 = CommitCost::SWAP_COST
+ VerifyCost::SWAP_COST
+ AMORTIZED_COST_PER_CHUNK * (SwapOp::CHUNKS as u64);

// The Subsidized cost of operations.
// Represent the cost of performing operations after recursion is introduced to mainnet.
pub(crate) const SUBSIDY_TRANSFER_COST: u64 = BASE_TRANSFER_COST * 5 / 100;
pub(crate) const SUBSIDY_TRANSFER_TO_NEW_COST: u64 = BASE_TRANSFER_TO_NEW_COST * 5 / 100;
pub(crate) const SUBSIDY_WITHDRAW_COST: u64 = BASE_WITHDRAW_COST;
pub(crate) const SUBSIDY_WITHDRAW_NFT_COST: u64 = BASE_WITHDRAW_NFT_COST;
pub(crate) const SUBSIDY_SWAP_COST: u64 = BASE_SWAP_COST;
pub(crate) const SUBSIDY_CHANGE_PUBKEY_OFFCHAIN_COST: u64 = BASE_CHANGE_PUBKEY_OFFCHAIN_COST;
pub(crate) const SUBSIDY_CHANGE_PUBKEY_ONCHAIN_COST: u64 = BASE_CHANGE_PUBKEY_ONCHAIN_COST;
pub(crate) const SUBSIDY_OLD_CHANGE_PUBKEY_OFFCHAIN_COST: u64 =
BASE_OLD_CHANGE_PUBKEY_OFFCHAIN_COST;
pub(crate) const SUBSIDY_CHANGE_PUBKEY_CREATE2_COST: u64 = BASE_CHANGE_PUBKEY_CREATE2_COST;
pub(crate) const SUBSIDY_MINT_NFT_COST: u64 = BASE_MINT_NFT_COST;
Loading

0 comments on commit dfee9cc

Please sign in to comment.