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

feat(main): base token gas oracle switch conversion rate to BigDecimal #220

Merged
merged 6 commits into from
May 20, 2024

Conversation

juan518munoz
Copy link

What ❔

Why ❔

Checklist

  • PR title corresponds to the body of PR (we generate changelog entries from PRs).
  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.
  • Code has been formatted via zk fmt and zk lint.
  • Spellcheck has been run via zk spellcheck.
  • Linkcheck has been run via zk linkcheck.

use tokio::{sync::Mutex, time::sleep};
use zksync_config::configs::BaseTokenFetcherConfig;
use zksync_dal::BigDecimal;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's adequate to use zksync_dal just to get BigDecimal from it. Please use the correct dependency (e.g. one that zksync_dal (maybe transitively) uses).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, fixed it.

Comment on lines 54 to 56
pub latest_to_eth_conversion_rate: Arc<StdMutex<BigDecimal>>,
http_client: reqwest::Client,
error_reporter: Arc<Mutex<ErrorReporter>>,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to combine both std and tokio mutex in the same structure? If we need tokio mutex just so that we can .await it (e.g. we do not hold the mutex guard across any await point), it should be safe to stick to std mutex everywhere (it's actually OK to use blocking mutexes even in asynchronous context, as stated even by tokio's own docs).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have moved all tokio mutexes to std as suggested.

.load(std::sync::atomic::Ordering::Relaxed),
)
fn conversion_rate(&self) -> anyhow::Result<BigDecimal> {
let lock = match self.latest_to_eth_conversion_rate.lock() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std mutex only returns an error if the mutex has been poisoned somewhere else, e.g. other thread has panicked while holding the mutex guard. It is an extreme situation that is extremely hard to handle gracefully. It is safe to simply unwrap the lock here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the match in favour of unwraping the lock. The tokio mutexes that are now std also unwrap now.

));
}
};
anyhow::Ok(lock.clone())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may simply write Ok(lock.clone()).

}
.to_string(),
)
.unwrap()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we return a Result<T, Err> instead of unwrapping?
Maybe an error can fall back to the previously set value, we probably have discussed this already, but wdy?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we unwrap() because we assume that the calculated gas prices won't overflow u64, this will only happen if the conversion rate is between what's specified as safe in the documentation.

If we were to return a Result then get_fee_model_params would need to handle this Result, which might cascade into a number of functions having to handle Results when they previously didn't.

.to_string(),
)
.unwrap()
.as_u64()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

.await
.context("Unable to parse the response of the native token conversion rate server")?;
let conversion_rate = BigDecimal::from_str(&conversion_rate_str)
.context("Unable to parse the response of the native token conversion rate server")?;
Copy link

@fkrause98 fkrause98 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:
Maybe we could also return what was the response from the server,
it can be annoying to see this error and don't know that the server is responding.

Otherwise, this depends more on the caller properly reporting the error and not the callee (the gas adjuster), so maybe it's not really required.

.ok_or_else(|| anyhow::anyhow!("Failed to fetch the native token conversion rate"))?;
let conversion_rate = BigDecimal::from_str(&conversion_rate)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following my comment above, this from_str returns a result, right?
So from_str already reports what was trying https://docs.rs/bigdecimal/latest/bigdecimal/enum.ParseBigDecimalError.html
to parse, so ok then, ignore what I said above.

.load(std::sync::atomic::Ordering::Relaxed),
)
fn conversion_rate(&self) -> anyhow::Result<BigDecimal> {
Ok(self.latest_to_eth_conversion_rate.lock().unwrap().clone())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could return a reference to avoid cloning.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, shouldn't self.latest_to_eth_conversion_rate.lock() be enough?

Copy link

@fkrause98 fkrause98 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a point here, but the related trait returns a Result<BigDecimal>, I think returning a reference here would overly complicate this interface (plus I don't think that's thread-safe), and maybe forcing the implementator to use an Arc<...> or an alternatively thread-safe type may be a bit too much? I think the current implementation is ok, as long as it does not hinder performance.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cloning bigdecimal is cheap, so I see no problem here.

Copy link

@popzxc popzxc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR can be merged to the "main" PR, and the remaining discussion can be kept there.

@juan518munoz juan518munoz merged commit 5a27dfb into base-token-gas-oracle May 20, 2024
7 of 11 checks passed
@juan518munoz juan518munoz deleted the base-token-gas-oracle-bigdecimal branch May 20, 2024 13:15
toni-calvin pushed a commit that referenced this pull request Aug 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants