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

Add benchmarks to transaction extensions #2726

Merged
merged 57 commits into from
Jan 11, 2024

Conversation

georgepisaltu
Copy link
Contributor

@georgepisaltu georgepisaltu commented Dec 15, 2023

Follow up effort on top of #2280

This PR implements benchmarking code for transaction extensions:

  • ChargeTransactionPayment
  • ChargeAssetTxPayment (asset-tx-payment)
  • ChargeAssetTxPayment (asset-conversion-tx-payment)
  • CheckWeight
  • CheckTxVersion
  • CheckSpecVersion
  • CheckNonce
  • CheckNonZeroSender
  • CheckMortality
  • CheckGenesis
  • CheckOnlySudoAccount
  • PrevalidateAttests

Extensions which still don't have benchmarks but could probably continue to use the default impl of Weight::zero() or call some existing weight function in the case of wrappers:

  • Test extensions
    • DummyExtension
    • WatchDummy
  • Wrappers
    • GenericTransactionExtension
    • TransactionExtension (chain-polkadot-bulletin)
  • Bridge extensions (see discussion below)
    • RefundTransactionExtensionAdapter

Each extension's TransactionExtensionBase::weight impl needs to use the resulting weight function and adapt existing runtimes' benchmarking configuration to these changes. So far, this has been done for:

  • ChargeTransactionPayment
  • ChargeAssetTxPayment (asset-tx-payment)
  • ChargeAssetTxPayment (asset-conversion-tx-payment)
  • CheckWeight
  • CheckTxVersion
  • CheckSpecVersion
  • CheckNonce
  • CheckNonZeroSender
  • CheckMortality
  • CheckGenesis
  • CheckOnlySudoAccount
  • PrevalidateAttests
  • RefundTransactionExtensionAdapter

Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@georgepisaltu georgepisaltu self-assigned this Dec 15, 2023
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@svyatonik
Copy link
Contributor

Re RefundTransactionExtensionAdapter - it is a bit complicated case && we already have some benchmarking there. I haven't checked - where this weight will be used. If it'll be added to weight of all runtime calls (as a base extrinsic weight or something like that), then it won't work for us - extensions does non-trivial things. So couple of details:

  1. first thing that bridge extensions do (in pre_dispatch/validate), is that they check whether the call is the call of one of bridge pallets or batch of those calls by matching. So for most calls the weight should be near zero and adding it to the base tx weight would mean that the signer overpays and we waste block space;
  2. then it does some checks in pre_dispatch that are then repeated by the calls themselves. They're mostly about reading tdb values and comparing them to arguments. Important thing there is that since those reads + comparisons are then duplicated, we do not account weight spent on this here, in extension;
  3. if those checks ^^^ are failed, then we do not include transaction to the block, so no weight is spent;
  4. in post_dispatch there are two possible options that could happen and actions on both branches are non-trivial. That's why we add max of those two weights to the weight of our bridge call. So if we'll add it to the base tx weight, it would mean duplication.

So the main question here is whether this weight you got through benchmarks is added to the base tx weight. If so, then please just left all as is (no additional benchmarks required for our extensions) - just return Weight::zero() from where it is required. Otherwise, please ping one of us (@paritytech/bridges-core ) - we'll help solve any issues here. Actually, I've been working on adapting bridge extensions to new scheme here: https://github.com/paritytech/polkadot-sdk/tree/sv-gav-tx-ext, but I think it was lost somewhere

@georgepisaltu
Copy link
Contributor Author

So the main question here is whether this weight you got through benchmarks is added to the base tx weight. If so, then please just left all as is (no additional benchmarks required for our extensions) - just return Weight::zero() from where it is required. Otherwise, please ping one of us (@paritytech/bridges-core ) - we'll help solve any issues here.

Regarding RefundTransactionExtensionAdapter, I agree the benchmarking there is complicated. I wanted to first come up with a worst case benchmark just to know it can be done, refining it to consume only what it should would have been incremental work. It could probably be done with "choice" arguments to the weight function to signal which code path would execute so we could choose an appropriate weight function. I'll try to come up with a POC for what is described above, but if it proves too difficult we may resort to accounting for this extension's weight in a different way and just return Weight::zero() in this extension's implementation.

Actually, I've been working on adapting bridge extensions to new scheme here: https://github.com/paritytech/polkadot-sdk/tree/sv-gav-tx-ext, but I think it was lost somewhere

This part is already done, check out the PR doing it and merging into the original PR. Feel free to create additional PRs with any fixes/improvements.

@georgepisaltu
Copy link
Contributor Author

So the main question here is whether this weight you got through benchmarks is added to the base tx weight. If so, then please just left all as is (no additional benchmarks required for our extensions) - just return Weight::zero() from where it is required.

Something I forgot to address in my original comment: in the current implementation I'm just aiming to have a weight associated with running the whole validate - prepare - post_dispatch flow in the trait impl (which is obviously flawed in the current iteration of the RefundTransactionExtensionAdapter benches). The TransactionExtensionBase::weight() function isn't hooked to any fee/weight management yet. My current understanding is that when run on-chain, these will need to consume weight on top of the base TX weight, but nothing stops off-chain workers from running validate while disregarding the weight. What I mean is that the weight function is there to associate a weight with each validate - prepare - post_dispatch flow; it's up to the extension user to do something (or nothing) with it. In our reference runtimes I think we will be charging weight for extensions, so if bridges deals with the weight of these extensions separately, having the weight function return Weight::zero() is probably correct.

Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@svyatonik
Copy link
Contributor

My current understanding is that when run on-chain, these will need to consume weight on top of the base TX weight

That is what worries me. As I said, for non-bridge transactions, our extensions are just (almost) noops in term of weight. So if we'll have non-zero weights for that tx and it'll be added by default to the tx base weight (like bas_weight = base_weight + SignedExtensions::pre_dispatch_weight + SignedExtensions::validate_weight + SignedExtensions::post_dispatch_weight), that'd be a problem. I'd just leave some big detailed comment (we may do that) on how to plugin this extension to the runtime with bridge pallets and just go with the "weight function return Weight::zero()" approach.

Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@georgepisaltu
Copy link
Contributor Author

@svyatonik at least for now, I reverted the benches for the bridge extensions altogether here.

@georgepisaltu georgepisaltu marked this pull request as ready for review December 20, 2023 11:38
@georgepisaltu georgepisaltu requested review from a team December 20, 2023 11:38
Copy link
Member

@ggwpez ggwpez left a comment

Choose a reason for hiding this comment

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

Code looks good.

Just about the design: why did you opt to create a new SystemExtensionsWeightInfo instead of just making it part of the WeightInfo of frame-system?
It causes a lot of changes (also breaking) and i dont really see the advantage.

polkadot/runtime/common/src/claims.rs Outdated Show resolved Hide resolved
//! Autogenerated weights for `pallet_transaction_payment`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
Copy link
Member

Choose a reason for hiding this comment

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

Will need to re-generate those with the bench bot.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are a bunch of weight files which were just copied, some of them are outdated as well. Everything will need to be benched again before a release.

use frame_support::traits::fungibles::Inspect as FnInspect;

#[cfg(feature = "runtime-benchmarks")]
impl pallet_asset_conversion_tx_payment::ExtConfig for Runtime {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we can get around copy&pasting this everywhere.
Maybe you can pull both functions into a shared crate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried really hard to make it generic but I found the setup is just too specific. One improvement here would be to move this to a BenchmarkHelper kind of thing in the regular config.

@@ -1521,6 +1548,11 @@ mod benchmarking {
}

benchmarks! {
where_clause { where <T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>>,
T: Config + Send + Sync + ExtConfig,
Copy link
Member

Choose a reason for hiding this comment

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

I understand that a TE itself should be Send + Sync, but i dont get why we need this on the Config as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need it for extensions holding a PhantomData, but not for the other ones. I removed it where applicable.

substrate/frame/system/src/extensions/check_genesis.rs Outdated Show resolved Hide resolved
@@ -22,7 +22,11 @@ use core::marker::PhantomData;

/// Weight functions for `{{pallet}}`.
pub struct WeightInfo<T>(PhantomData<T>);
{{#if (eq pallet "frame_system_extensions")}}
Copy link
Member

Choose a reason for hiding this comment

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

Looks a bit hacky, see my review comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't feel hacky to me, it's basically the same as the model for the frame_system weights in the other templates. They also get special treatment because of the name, like in substrate/.maintain/frame-weight-template.hbs.

Copy link
Member

@ggwpez ggwpez Jan 9, 2024

Choose a reason for hiding this comment

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

Yea but its not neccecary here since you can move the TE benchmarks to a new frame-system-ext-benchmarking crate.

PS: But then it will need to use the weight trait from a different crate in frame-system, that is also not so nice...

@georgepisaltu
Copy link
Contributor Author

Just about the design: why did you opt to create a new SystemExtensionsWeightInfo instead of just making it part of the WeightInfo of frame-system? It causes a lot of changes (also breaking) and i dont really see the advantage.

I actually think it's cleaner having them separate since the code being benchmarked in extensions does very different things compared to the system pallet, even though they both depend on frame_system::Config. Main advantage is this way you can easily choose to ignore extension weights, which would be backwards compatible with what we have now, and have real weights for the rest of the system stuff. Given how the current frame_system weights are implemented now, with the benches in a different crate, I think it fits fine.

@paritytech paritytech deleted a comment from paritytech-cicd-pr Jan 5, 2024
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@paritytech paritytech deleted a comment from paritytech-cicd-pr Jan 5, 2024
@ggwpez ggwpez added the T1-FRAME This PR/Issue is related to core FRAME, the framework. label Jan 9, 2024
ggwpez added a commit that referenced this pull request Jan 9, 2024
Removing some bounds as it came up in
#2726 while still keeping
`Send + Sync` capabilities.

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Bastian Köcher <git@kchr.de>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@paritytech paritytech deleted a comment from paritytech-cicd-pr Jan 10, 2024
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@paritytech paritytech deleted a comment from paritytech-cicd-pr Jan 10, 2024
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@paritytech paritytech deleted a comment from paritytech-cicd-pr Jan 10, 2024
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
@gavofyork gavofyork merged commit b18c199 into paritytech:gav-tx-ext Jan 11, 2024
121 of 122 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T1-FRAME This PR/Issue is related to core FRAME, the framework.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants