Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make set token multiplier optional #2696

Merged
merged 4 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 54 additions & 50 deletions core/node/base_token_adjuster/src/base_token_ratio_persister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::{cmp::max, fmt::Debug, sync::Arc, time::Duration};
use anyhow::Context as _;
use tokio::{sync::watch, time::sleep};
use zksync_config::configs::base_token_adjuster::BaseTokenAdjusterConfig;
use zksync_contracts::chain_admin_contract;
use zksync_dal::{ConnectionPool, Core, CoreDal};
use zksync_eth_client::{BoundEthInterface, Options};
use zksync_external_price_api::PriceAPIClient;
Expand All @@ -15,18 +14,23 @@ use zksync_types::{
Address, U256,
};

#[derive(Debug, Clone)]
pub struct BaseTokenRatioPersisterL1Params {
pub eth_client: Box<dyn BoundEthInterface>,
pub gas_adjuster: Arc<dyn TxParamsProvider>,
pub token_multiplier_setter_account_address: Address,
pub chain_admin_contract: Contract,
pub diamond_proxy_contract_address: Address,
pub chain_admin_contract_address: Option<Address>,
}

#[derive(Debug, Clone)]
pub struct BaseTokenRatioPersister {
pool: ConnectionPool<Core>,
config: BaseTokenAdjusterConfig,
base_token_address: Address,
price_api_client: Arc<dyn PriceAPIClient>,
eth_client: Box<dyn BoundEthInterface>,
gas_adjuster: Arc<dyn TxParamsProvider>,
token_multiplier_setter_account_address: Address,
chain_admin_contract: Contract,
diamond_proxy_contract_address: Address,
chain_admin_contract_address: Option<Address>,
l1_params: Option<BaseTokenRatioPersisterL1Params>,
}

impl BaseTokenRatioPersister {
Expand All @@ -36,25 +40,14 @@ impl BaseTokenRatioPersister {
config: BaseTokenAdjusterConfig,
base_token_address: Address,
price_api_client: Arc<dyn PriceAPIClient>,
eth_client: Box<dyn BoundEthInterface>,
gas_adjuster: Arc<dyn TxParamsProvider>,
token_multiplier_setter_account_address: Address,
diamond_proxy_contract_address: Address,
chain_admin_contract_address: Option<Address>,
l1_params: Option<BaseTokenRatioPersisterL1Params>,
) -> Self {
let chain_admin_contract = chain_admin_contract();

Self {
pool,
config,
base_token_address,
price_api_client,
eth_client,
gas_adjuster,
token_multiplier_setter_account_address,
chain_admin_contract,
diamond_proxy_contract_address,
chain_admin_contract_address,
l1_params,
}
}

Expand Down Expand Up @@ -90,53 +83,63 @@ impl BaseTokenRatioPersister {
let new_ratio = self.retry_fetch_ratio().await?;
self.persist_ratio(new_ratio).await?;

let max_attempts = self.config.l1_tx_sending_max_attempts;
let sleep_duration = self.config.l1_tx_sending_sleep_duration();
let mut result: anyhow::Result<()> = Ok(());
let mut prev_base_fee_per_gas: Option<u64> = None;
let mut prev_priority_fee_per_gas: Option<u64> = None;
if let Some(l1_params) = &self.l1_params {
ischasny marked this conversation as resolved.
Show resolved Hide resolved
let max_attempts = self.config.l1_tx_sending_max_attempts;
let sleep_duration = self.config.l1_tx_sending_sleep_duration();
let mut result: anyhow::Result<()> = Ok(());
let mut prev_base_fee_per_gas: Option<u64> = None;
let mut prev_priority_fee_per_gas: Option<u64> = None;

for attempt in 0..max_attempts {
let (base_fee_per_gas, priority_fee_per_gas) =
self.get_eth_fees(prev_base_fee_per_gas, prev_priority_fee_per_gas);
for attempt in 0..max_attempts {
let (base_fee_per_gas, priority_fee_per_gas) =
self.get_eth_fees(&l1_params, prev_base_fee_per_gas, prev_priority_fee_per_gas);

result = self
.send_ratio_to_l1(new_ratio, base_fee_per_gas, priority_fee_per_gas)
.await;
if let Some(err) = result.as_ref().err() {
tracing::info!(
result = self
.send_ratio_to_l1(
&l1_params,
new_ratio,
base_fee_per_gas,
priority_fee_per_gas,
)
.await;
if let Some(err) = result.as_ref().err() {
tracing::info!(
"Failed to update base token multiplier on L1, attempt {}, base_fee_per_gas {}, priority_fee_per_gas {}: {}",
attempt + 1,
base_fee_per_gas,
priority_fee_per_gas,
err
);
tokio::time::sleep(sleep_duration).await;
prev_base_fee_per_gas = Some(base_fee_per_gas);
prev_priority_fee_per_gas = Some(priority_fee_per_gas);
} else {
tracing::info!(
tokio::time::sleep(sleep_duration).await;
prev_base_fee_per_gas = Some(base_fee_per_gas);
prev_priority_fee_per_gas = Some(priority_fee_per_gas);
} else {
tracing::info!(
"Updated base token multiplier on L1: numerator {}, denominator {}, base_fee_per_gas {}, priority_fee_per_gas {}",
new_ratio.numerator.get(),
new_ratio.denominator.get(),
base_fee_per_gas,
priority_fee_per_gas
);
return result;
return result;
}
}
result
} else {
Ok(())
}
result
}

fn get_eth_fees(
&self,
l1_params: &BaseTokenRatioPersisterL1Params,
prev_base_fee_per_gas: Option<u64>,
prev_priority_fee_per_gas: Option<u64>,
) -> (u64, u64) {
// Use get_blob_tx_base_fee here instead of get_base_fee to optimise for fast inclusion.
// get_base_fee might cause the transaction to be stuck in the mempool for 10+ minutes.
let mut base_fee_per_gas = self.gas_adjuster.as_ref().get_blob_tx_base_fee();
let mut priority_fee_per_gas = self.gas_adjuster.as_ref().get_priority_fee();
let mut base_fee_per_gas = l1_params.gas_adjuster.as_ref().get_blob_tx_base_fee();
let mut priority_fee_per_gas = l1_params.gas_adjuster.as_ref().get_priority_fee();
if let Some(x) = prev_priority_fee_per_gas {
// Increase `priority_fee_per_gas` by at least 20% to prevent "replacement transaction under-priced" error.
priority_fee_per_gas = max(priority_fee_per_gas, (x * 6) / 5 + 1);
Expand Down Expand Up @@ -213,30 +216,31 @@ impl BaseTokenRatioPersister {

async fn send_ratio_to_l1(
&self,
l1_params: &BaseTokenRatioPersisterL1Params,
api_ratio: BaseTokenAPIRatio,
base_fee_per_gas: u64,
priority_fee_per_gas: u64,
) -> anyhow::Result<()> {
let fn_set_token_multiplier = self
let fn_set_token_multiplier = l1_params
.chain_admin_contract
.function("setTokenMultiplier")
.context("`setTokenMultiplier` function must be present in the ChainAdmin contract")?;

let calldata = fn_set_token_multiplier
.encode_input(
&(
Token::Address(self.diamond_proxy_contract_address),
Token::Address(l1_params.diamond_proxy_contract_address),
Token::Uint(api_ratio.numerator.get().into()),
Token::Uint(api_ratio.denominator.get().into()),
)
.into_tokens(),
)
.context("failed encoding `setTokenMultiplier` input")?;

let nonce = (*self.eth_client)
let nonce = (*l1_params.eth_client)
.as_ref()
.nonce_at_for_account(
self.token_multiplier_setter_account_address,
l1_params.token_multiplier_setter_account_address,
BlockNumber::Pending,
)
.await
Expand All @@ -251,17 +255,17 @@ impl BaseTokenRatioPersister {
..Default::default()
};

let signed_tx = self
let signed_tx = l1_params
.eth_client
.sign_prepared_tx_for_addr(
calldata,
self.chain_admin_contract_address.unwrap(),
l1_params.chain_admin_contract_address.unwrap(),
options,
)
.await
.context("cannot sign a `setTokenMultiplier` transaction")?;

let hash = (*self.eth_client)
let hash = (*l1_params.eth_client)
.as_ref()
.send_raw_tx(signed_tx.raw_tx)
.await
Expand All @@ -270,7 +274,7 @@ impl BaseTokenRatioPersister {
let max_attempts = self.config.l1_receipt_checking_max_attempts;
let sleep_duration = self.config.l1_receipt_checking_sleep_duration();
for _i in 0..max_attempts {
let maybe_receipt = (*self.eth_client)
let maybe_receipt = (*l1_params.eth_client)
.as_ref()
.tx_receipt(hash)
.await
Expand Down
2 changes: 1 addition & 1 deletion core/node/base_token_adjuster/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub use self::{
base_token_ratio_persister::BaseTokenRatioPersister,
base_token_ratio_persister::{BaseTokenRatioPersister, BaseTokenRatioPersisterL1Params},
base_token_ratio_provider::{DBBaseTokenRatioProvider, NoOpRatioProvider},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use zksync_base_token_adjuster::BaseTokenRatioPersister;
use zksync_base_token_adjuster::{BaseTokenRatioPersister, BaseTokenRatioPersisterL1Params};
use zksync_config::{
configs::{base_token_adjuster::BaseTokenAdjusterConfig, wallets::Wallets},
ContractsConfig,
};
use zksync_contracts::chain_admin_contract;
use zksync_eth_client::clients::PKSigningClient;
use zksync_types::L1ChainId;

Expand Down Expand Up @@ -81,37 +82,37 @@ impl WiringLayer for BaseTokenRatioPersisterLayer {
.contracts_config
.base_token_addr
.expect("base token address is not set");
let diamond_proxy_contract_address = self.contracts_config.diamond_proxy_addr;
let chain_admin_contract_address = self.contracts_config.chain_admin_addr;
let token_multiplier_setter_wallet = self
.wallets_config
.token_multiplier_setter
.expect("base token adjuster wallet is not set")
.wallet;

let tms_private_key = token_multiplier_setter_wallet.private_key();
let tms_address = token_multiplier_setter_wallet.address();
let EthInterfaceResource(query_client) = input.eth_client;
let mut l1_params: Option<BaseTokenRatioPersisterL1Params> = None;
if let Some(token_multiplier_setter) = self.wallets_config.token_multiplier_setter {
ischasny marked this conversation as resolved.
Show resolved Hide resolved
let tms_private_key = token_multiplier_setter.wallet.private_key();
let tms_address = token_multiplier_setter.wallet.address();
let EthInterfaceResource(query_client) = input.eth_client;

let signing_client = PKSigningClient::new_raw(
tms_private_key.clone(),
self.contracts_config.diamond_proxy_addr,
self.config.default_priority_fee_per_gas,
#[allow(clippy::useless_conversion)]
self.l1_chain_id.into(),
query_client.clone().for_component("base_token_adjuster"),
);
let signing_client = PKSigningClient::new_raw(
tms_private_key.clone(),
self.contracts_config.diamond_proxy_addr,
self.config.default_priority_fee_per_gas,
#[allow(clippy::useless_conversion)]
self.l1_chain_id.into(),
query_client.clone().for_component("base_token_adjuster"),
);
l1_params = Some(BaseTokenRatioPersisterL1Params {
eth_client: Box::new(signing_client),
gas_adjuster: input.tx_params.0,
token_multiplier_setter_account_address: tms_address,
chain_admin_contract: chain_admin_contract(),
diamond_proxy_contract_address: self.contracts_config.diamond_proxy_addr,
chain_admin_contract_address: self.contracts_config.chain_admin_addr,
});
}

let persister = BaseTokenRatioPersister::new(
master_pool,
self.config,
base_token_addr,
price_api_client.0,
Box::new(signing_client),
input.tx_params.0,
tms_address,
diamond_proxy_contract_address,
chain_admin_contract_address,
l1_params,
);

Ok(Output { persister })
Expand Down
Loading