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: benchmark foreign investments worst case #1565

Merged
merged 27 commits into from
Sep 25, 2023
Merged

Conversation

wischli
Copy link
Contributor

@wischli wischli commented Sep 22, 2023

Description

  • Adds ForeignInvestmentBenchmarkHelper which provides the setup required for benchmarking the heaviest foreign investment call
  • Adds benchmarking mod to pallet-liquidity-pools which benches an incoming CollectRedeem message by executing handle_collect_redemption
    • NOTE: Skipped the InboundQueue since this complicates the investor setup: Right now, the investor account is created during the pool creation of pool_system::PoolBenchmarkHelper and thus just some Substrate account id. However, for the InboundQueue it would have to be a AccountConverter<Runtime, LocationToAccountId>::convert((sender_domain, investor_bytes)).
  • Feature creep: Renames pallet_foreign_investments::<T>::Config::Rate to BalanceRatio

TODO

  • Discuss how to move forward: Do we want to defensively stick to the hardcoded weights?
    • If so, we should not add LiquidityPools to the runtimes' benchmark list
    • Else, I would continue writing benchmarks for existing extrinsics such that we have everything covered properly: an inbound messages by the FI worst case (handle_collect_redemption) and extrinsics by their corresponding benchmarks
  • Maybe: Right now, the pallet-liquidity-pools benchmarks cannot be unit tested, because the existing mock is insufficient. If running unit tests is desired, I propose to enable this in a subsequent PR.

Justification about heaviest FI call

  • In the context of pallet-foreign-investments, the heaviest action (measured by amount of reads and writes) is collecting a redemption when there exists an InvestmentState which swaps from foreign to pool
  • By collecting the redemption, a swap from pool to foreign emerges which needs to be resolved in handle_concurrent_swap_orders by comparing with the existing swap from the investment

About the weight

For presentation purposes, I temporarily added the generated weight file. This must be removed before merging as otherwise executing benchmarks for pallet-liquidity-pools would remove all hardcoded values.

When looking at the results of executing the benchmark on my local machine, the total weight is ~55% of the current hardcoded one. The PoV size is ~80% of the hardcoded one. For details, see the WIP Weights Sheet. I suppose the locally generated weights are close enough to our benchmark runner, since the results are similar.

		Weight::from_parts(236_000_000, 71940)
			.saturating_add(T::DbWeight::get().reads(20))
			.saturating_add(T::DbWeight::get().writes(17))

Checklist:

  • I have added Rust doc comments to structs, enums, traits and functions
  • I have made corresponding changes to the documentation
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or that my feature works

@wischli wischli self-assigned this Sep 22, 2023
@wischli wischli added the I8-enhancement An additional feature. label Sep 22, 2023
@@ -152,7 +152,7 @@ pub mod pallet {

/// Type for price ratio for cost of incoming currency relative to
/// outgoing
type Rate: Parameter
type BalanceRatio: Parameter
Copy link
Contributor Author

@wischli wischli Sep 22, 2023

Choose a reason for hiding this comment

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

Sorry for feature creeping. This change does not have any functional impact as it's just renaming.

@@ -0,0 +1,78 @@

//! Autogenerated weights for `pallet_liquidity_pools`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

NOTE: Committed solely for demonstration purpose, will be removed before merging!

Copy link
Contributor

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

Love how clean are you getting this given that is quite difficult benchmark. 💯

Comment on lines 74 to 87
/// Returns
/// * The substrate investor address
/// * The investment id
/// * The pool currency id
/// * The foreign currency id
/// * A trading account which can bidirectionally fulfill swap orders for
/// the (foreign, pool) currency pair
fn bench_prepare_foreign_investments_setup() -> (
Self::AccountId,
Self::InvestmentId,
Self::CurrencyId,
Self::CurrencyId,
Self::AccountId,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a plain struct along with this trait can avoid errors when reading from these values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

) {
let pool_id = Default::default();
let pool_admin: T::AccountId = frame_benchmarking::account("pool_admin", 0, 0);
<T::PoolInspect as PoolBenchmarkHelper>::bench_create_pool(pool_id, &pool_admin);
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment: I really like how the bench_* methods are called inside bench_* methods, leaving a clean API to use from the benchmark side with 0 knowledge about what's happening under the hood. i.e. the pool_id used is totally transparent here ❤️

Comment on lines +526 to +531
let pool_account = PoolLocator { pool_id }.into_account_truncating();
frame_support::assert_ok!(T::Tokens::mint_into(
POOL_CURRENCY,
&pool_account,
POOL_ACCOUNT_BALANCE.into()
));
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious, why is this minting now needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was taken from the integration tests when I was debugging BalanceTooLow errors. So it might not be necessary but I believe it still is.

When we process a redemption of tranche tokens, the pool account needs to have native balance which is exchanged for these tranche tokens.

In contrast, we don't need to fund the pool account with tranche tokens as these are minted when processing an investment.

mustermeiszer
mustermeiszer previously approved these changes Sep 25, 2023
Copy link
Collaborator

@mustermeiszer mustermeiszer left a comment

Choose a reason for hiding this comment

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

Sick! Whats your final feeling regarding the adaption of the process_msg weight?

I am personally leaning torwards keeping it as is an heavier. But might be paranoia...

@wischli could you include the changes from #1562, then we do not need to wait for CI 2 times.

@wischli wischli marked this pull request as ready for review September 25, 2023 08:25
@wischli wischli requested a review from lemunozm September 25, 2023 09:27
@mustermeiszer mustermeiszer mentioned this pull request Sep 25, 2023
4 tasks
@wischli wischli enabled auto-merge (squash) September 25, 2023 12:39
Copy link
Contributor

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

LGTM!

@wischli wischli merged commit 255f8fd into main Sep 25, 2023
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I8-enhancement An additional feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants