Skip to content

Commit

Permalink
Merge #1440
Browse files Browse the repository at this point in the history
1440: Fee free account  r=Deniallugo a=Barichek



Co-authored-by: Ihor Barenblat <[email protected]>
Co-authored-by: Ihor Barenblat <[email protected]>
  • Loading branch information
3 people authored Mar 15, 2021
2 parents bdfcf39 + 8a41a00 commit c5422d3
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 18 deletions.
1 change: 1 addition & 0 deletions changelog/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ All notable changes to the core components will be documented in this file.
operations.
- (`eth_client`): Added `get_tx`, `create_contract` methods to `EthereumGateway`, `get_web3_transport` method to
ETHDirectClient.
- (`api_server`): Support for accounts that don't have to pay fees (e.g. network service accounts) was added.

### Fixed

Expand Down
99 changes: 83 additions & 16 deletions core/bin/zksync_api/src/api_server/rest/v1/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,12 @@ mod tests {
async fn new() -> anyhow::Result<(Client, Self)> {
let (core_client, core_server) = submit_txs_loopback();

let cfg = TestServerConfig::default();
let mut cfg = TestServerConfig::default();
cfg.config
.api
.common
.fee_free_accounts
.push(AccountId(0xfee));
let pool = cfg.pool.clone();
cfg.fill_database().await?;

Expand Down Expand Up @@ -476,6 +481,20 @@ mod tests {
}
}

#[actix_rt::test]
#[cfg_attr(
not(feature = "api_test"),
ignore = "Use `zk test rust-api` command to perform this test"
)]
async fn test_rust_api() -> anyhow::Result<()> {
// TODO: ZKS-561
test_transactions_scope().await?;
test_bad_fee_token().await?;
test_fast_processing_flag().await?;
test_fee_free_accounts().await?;
Ok(())
}

#[actix_rt::test]
#[cfg_attr(
not(feature = "api_test"),
Expand All @@ -498,11 +517,6 @@ mod tests {
Ok(())
}

#[actix_rt::test]
#[cfg_attr(
not(feature = "api_test"),
ignore = "Use `zk test rust-api` command to perform this test"
)]
async fn test_transactions_scope() -> anyhow::Result<()> {
let (client, server) = TestServer::new().await?;

Expand Down Expand Up @@ -665,11 +679,6 @@ mod tests {
/// - Attempt to pay fees in an inappropriate token fails for single txs.
/// - Attempt to pay fees in an inappropriate token fails for single batch.
/// - Batch with an inappropriate token still can be processed if the fee is covered with a common token.
#[actix_rt::test]
#[cfg_attr(
not(feature = "api_test"),
ignore = "Use `zk test rust-api` command to perform this test"
)]
async fn test_bad_fee_token() -> anyhow::Result<()> {
let (client, server) = TestServer::new().await?;

Expand Down Expand Up @@ -781,16 +790,74 @@ mod tests {
Ok(())
}

/// This test checks the following:
///
/// Fee free account can pay zero fee in single tx.
/// Not a fee free account can't pay zero fee in single tx.
async fn test_fee_free_accounts() -> anyhow::Result<()> {
let (client, server) = TestServer::new().await?;

let from1 = ZkSyncAccount::rand();
from1.set_account_id(Some(AccountId(0xfee)));
let to1 = ZkSyncAccount::rand();

// Submit transaction with a zero fee by the fee free account
let (tx1, eth_sig1) = from1.sign_transfer(
TokenId(0),
"ETH",
0u64.into(),
0u64.into(),
&to1.address,
Some(Nonce(0)),
false,
Default::default(),
);
let transfer1 = ZkSyncTx::Transfer(Box::new(tx1));
client
.submit_tx(
transfer1.clone(),
eth_sig1.map(TxEthSignature::EthereumSignature),
None,
)
.await
.expect("fee free account transaction fails");

let from2 = ZkSyncAccount::rand();
from2.set_account_id(Some(AccountId(0xbee)));
let to2 = ZkSyncAccount::rand();

// Submit transaction with a zero fee not by the fee free account
let (tx2, eth_sig2) = from2.sign_transfer(
TokenId(0),
"ETH",
0u64.into(),
0u64.into(),
&to2.address,
Some(Nonce(0)),
false,
Default::default(),
);
let transfer2 = ZkSyncTx::Transfer(Box::new(tx2));
client
.submit_tx(
transfer2.clone(),
eth_sig2.map(TxEthSignature::EthereumSignature),
None,
)
.await
.unwrap_err()
.to_string()
.contains("Transaction fee is too low");

server.stop().await;
Ok(())
}

/// This test checks the following criteria:
///
/// - Attempt to submit non-withdraw transaction with the enabled fast-processing.
/// - Attempt to submit non-withdraw transaction with the disabled fast-processing.
/// - Attempt to submit withdraw transaction with the enabled fast-processing.
#[actix_rt::test]
#[cfg_attr(
not(feature = "api_test"),
ignore = "Use `zk test rust-api` command to perform this test"
)]
async fn test_fast_processing_flag() -> anyhow::Result<()> {
let (client, server) = TestServer::new().await?;

Expand Down
17 changes: 15 additions & 2 deletions core/bin/zksync_api/src/api_server/tx_sender.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Helper module to submit transactions into the zkSync Network.
// Built-in uses
use std::iter::FromIterator;
use std::{collections::HashSet, fmt::Display, str::FromStr};

// External uses
Expand All @@ -21,7 +22,7 @@ use zksync_types::{
tx::{
EthBatchSignData, EthBatchSignatures, EthSignData, SignedZkSyncTx, TxEthSignature, TxHash,
},
Address, BatchFee, Fee, Token, TokenId, TokenLike, TxFeeTypes, ZkSyncTx, H160,
AccountId, Address, BatchFee, Fee, Token, TokenId, TokenLike, TxFeeTypes, ZkSyncTx, H160,
};

// Local uses
Expand All @@ -45,6 +46,8 @@ pub struct TxSender {
pub blocks: BlockDetailsCache,
/// Mimimum age of the account for `ForcedExit` operations to be allowed.
pub forced_exit_minimum_account_age: chrono::Duration,
/// List of account IDs that do not have to pay fees for operations.
pub fee_free_accounts: HashSet<AccountId>,
pub enforce_pubkey_change_fee: bool,
// Limit the number of both transactions and Ethereum signatures per batch.
pub max_number_of_transactions_per_batch: usize,
Expand Down Expand Up @@ -147,6 +150,7 @@ impl TxSender {

enforce_pubkey_change_fee: config.api.common.enforce_pubkey_change_fee,
forced_exit_minimum_account_age,
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,
}
Expand Down Expand Up @@ -223,7 +227,16 @@ impl TxSender {
.get_ethereum_sign_message(token.clone())
.map(String::into_bytes);

let tx_fee_info = tx.get_fee_info();
let is_whitelisted_initiator = tx
.account_id()
.map(|account_id| self.fee_free_accounts.contains(&account_id))
.unwrap_or(false);

let tx_fee_info = if !is_whitelisted_initiator {
tx.get_fee_info()
} else {
None
};

let sign_verify_channel = self.sign_verify_requests.clone();
let ticker_request_sender = self.ticker_requests.clone();
Expand Down
6 changes: 6 additions & 0 deletions core/lib/config/src/configs/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use serde::Deserialize;
/// Built-in uses
use std::net::SocketAddr;
// Workspace uses
use zksync_types::AccountId;
// Local uses
use crate::envy_load;

Expand Down Expand Up @@ -46,6 +48,8 @@ pub struct Common {
// Determines the required minimum account age for `ForcedExit` operation to be allowed.
// Type of value is seconds.
pub forced_exit_minimum_account_age_secs: u64,
/// List of account IDs that do not have to pay fees for operations.
pub fee_free_accounts: Vec<AccountId>,
pub enforce_pubkey_change_fee: bool,

pub max_number_of_transactions_per_batch: u64,
Expand Down Expand Up @@ -154,6 +158,7 @@ mod tests {
enforce_pubkey_change_fee: true,
max_number_of_transactions_per_batch: 200,
max_number_of_authors_per_batch: 10,
fee_free_accounts: vec![AccountId(4078), AccountId(387)],
},
admin: AdminApi {
port: 8080,
Expand Down Expand Up @@ -188,6 +193,7 @@ mod tests {
let config = r#"
API_COMMON_CACHES_SIZE="10000"
API_COMMON_FORCED_EXIT_MINIMUM_ACCOUNT_AGE_SECS="0"
API_COMMON_FEE_FREE_ACCOUNTS=4078,387
API_COMMON_ENFORCE_PUBKEY_CHANGE_FEE=true
API_COMMON_MAX_NUMBER_OF_TRANSACTIONS_PER_BATCH=200
API_COMMON_MAX_NUMBER_OF_AUTHORS_PER_BATCH=10
Expand Down
2 changes: 2 additions & 0 deletions etc/env/base/api.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ caches_size=10000
# value at least 24 hours for production.
# Type of value is seconds.
forced_exit_minimum_account_age_secs=0
# List of account IDs that do not have to pay fees for operations.
fee_free_accounts=[]

# Ability to perform change pub key with zero fee
enforce_pubkey_change_fee=true
Expand Down

0 comments on commit c5422d3

Please sign in to comment.