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

WIP: implement StorageWeightReclaim as wrapping transaction extension with weight #5234

Draft
wants to merge 32 commits into
base: george/restore-gav-tx-ext
Choose a base branch
from

Conversation

gui1117
Copy link
Contributor

@gui1117 gui1117 commented Aug 5, 2024

Implement StorageWeightReclaim as a transaction extension that wraps around all the transaction extensions.

This is because transaction extension weight is not part of base extrinsic weight. So we should trigger before all extensions and reclaim after all extensions to get accurate post info.

old StorageWeightReclaim is deprecated

TODO:

  • fix benchmarks so that ProofSizeExt is available or that the worst-case code is covered in some way
  • maybe modify benchmark scripts
  • execute benchmarks and link weights.
  • can be rewritten using 2 extesions: record and reclaim if prefered
  • prdoc

@gui1117 gui1117 force-pushed the gui-storage-proof-size-reclaim-more-accurate branch from b05e68c to 76d3373 Compare August 5, 2024 07:09
@skunert
Copy link
Contributor

skunert commented Aug 5, 2024

Very nice!

can be rewritten using 2 extesions: record and reclaim if prefered

How would the two communicate? Would we need a new StorageItem for them to read and write?
From the top of my head I currently don't see a benefit from splitting them, do you have anything in mind?

@gui1117
Copy link
Contributor Author

gui1117 commented Aug 5, 2024

can be rewritten using 2 extesions: record and reclaim if prefered

How would the two communicate? Would we need a new StorageItem for them to read and write? From the top of my head I currently don't see a benefit from splitting them, do you have anything in mind?

extending the dispatch context to transaction extension also
https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch_context/index.html

or using a storage item.

But wrapping type seems ok.

@s0me0ne-unkn0wn
Copy link
Contributor

Having a storage item and writing into it in pre_dispatch would affect the proof size by itself (a classical "the observer influences what he observes"). It can be mitigated by adjusting the calculations by a benchmarked proof size of that operation, but the wrapper solution looks cleaner in that sense, anyway.

@gui1117
Copy link
Contributor Author

gui1117 commented Aug 5, 2024

Having a storage item and writing into it in pre_dispatch would affect the proof size by itself (a classical "the observer influences what he observes"). It can be mitigated by adjusting the calculations by a benchmarked proof size of that operation, but the wrapper solution looks cleaner in that sense, anyway.

I thought writing into a storage without reading it before would not leak anything into the proof.

Copy link
Contributor

@georgepisaltu georgepisaltu left a comment

Choose a reason for hiding this comment

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

First round of review, looking good so far 👍

@@ -945,6 +945,10 @@ impl pallet_xcm_bridge_hub_router::Config<ToWestendXcmRouterInstance> for Runtim
type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId;
}

impl cumulus_pallet_weight_reclaim_tx::Config for Runtime {
type WeightInfo = ();
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be nice to run a bot bench on this new pallet and get some weights once we're set on a final version of the code. Same for other runtimes.

//! add [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim)
//! to that list. For maximum efficiency, make sure that `StorageWeightReclaim` is last in the list.
//! set [`StorageWeightReclaim`](cumulus_pallet_weight_reclaim_tx::StorageWeightReclaim)
//! as a warpper of that list.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd add something like "in order to catch the whole PoV size, it's required that this extension wraps all the other transaction extensions of the runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in ea81a0f

cumulus/pallets/weight-reclaim-tx/src/lib.rs Outdated Show resolved Hide resolved
}
}

// Make this extension "invisible" from the outside (ie metadata type information)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why would we not want this extension to show up in the metadata? Especially since this along with CheckMetadataHash would alert us if something changes to the extension pipeline, this extension included.

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 don't know how UI code is written and if it expects a list of transaction extension or if it can handle more complex structure.
  • I copied the design from SkipIfCheckFeeless which is also invisible from the outside.

I don't mind anything, but we must make sure UI knows how to handle nested transaction extensions.

Copy link
Contributor

Choose a reason for hiding this comment

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

Until we can confirm the UI doesn't break or we get support in the UI, let's keep it invisible 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

How would an extension that has no implication on the signed and raw payload the tx break any UI?

As in, with our without this extension, the same bytes are a valid tx, so...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How would an extension that has no implication on the signed and raw payload the tx break any UI?

As in, with our without this extension, the same bytes are a valid tx, so...?

I expect UI frameworks to do some match on the transaction extension identifiers (which weight reclaim implements in an invisible way), but if they are doing some match on the transaction extension type to get information about what needs to be provided then it will break.

Copy link
Contributor

Choose a reason for hiding this comment

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

As far as I'm aware, client libraries (like Subxt) mostly just match on the identifiers, since they usually need to implement some sort of custom logic for how to handle each extension anyway. So if this extension is "invisible" in that way then I don't see it causing an issue offhand!

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 fixed the implementation, it is still invisible, but should be correctly implemented. 375543d

Comment on lines 156 to 157
// Trade-off: we could move it to `prepare` but better be accurate on reclaim than fast on
// `validate`
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

cumulus/pallets/weight-reclaim-tx/src/lib.rs Outdated Show resolved Hide resolved
cumulus/pallets/weight-reclaim-tx/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines 191 to 192
let inner_weight =
S::post_dispatch_details(inner_pre, info, post_info, len, result, context)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be computed using post_dispatch. The post_dispatch_details function should not be used explicitly because, unlike post_dispatch, it does not carry over the reduced weight through a mutable reference to the PostDispatchInfo. It would return the correct actual weight used, but it wouldn't update the post_info along the way, and some extensions rely on it, it's basically their weight meter.

For more info into the way it works, look at the TransactionExtension impl at substrate/primitives/runtime/src/traits/transaction_extension/mod.rs:498.

I wanted to make post_dispatch_details take a mutable reference to post_info as well, but I figured I would only encourage people to use it the unintended way.

The suggestion below can probably be nicer with a match, but the inner_weight calculation will change anyway once the post dispatch weight subtraction instead of accrual is implemented.

Suggested change
let inner_weight =
S::post_dispatch_details(inner_pre, info, post_info, len, result, context)?;
let mut actual_post_info = *post_info;
S::post_dispatch(inner_pre, info, &mut actual_post_info, len, result, context)?;
let inner_weight = actual_post_info
.actual_weight
.map(|actual_weight| actual_weight.saturating_sub(post_info.actual_weight.unwrap()));

Copy link
Contributor Author

@gui1117 gui1117 Aug 5, 2024

Choose a reason for hiding this comment

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

I see, maybe the post_dispatch_details implementation for tuples should log a warning, or have a debug error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implementing post_dispatch_details prevent us from returning the correct pays_fee if a transaction extension modified it.

It may be more accurate to implement post_dispatch I did at: 4d99a45

}

#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
Copy link
Contributor

Choose a reason for hiding this comment

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

It probably needs a custom MockWeights: frame_system::ExtensionsWeightInfo that you can control and assert in tests for CheckWeight's post_dispatch. To make the tests more accurate, some mock weights can be used for this pallet as well, instead of ().

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 set up configuration for better tests in eb0cdff but I will wait for the deccumulating/refining post dispatch info implementation.

@s0me0ne-unkn0wn s0me0ne-unkn0wn linked an issue Aug 6, 2024 that may be closed by this pull request
@paritytech-cicd-pr
Copy link

The CI pipeline was cancelled due to failure one of the required jobs.
Job name: test-linux-stable 2/3
Logs: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/6960444

fellowship-merge-bot bot pushed a commit to polkadot-fellows/runtimes that referenced this pull request Aug 13, 2024
I propose to move PoV-reclaim to the next release.

It can happen that the amount to reclaim is overestimated
paritytech/polkadot-sdk#5229.

Improvements (paritytech/polkadot-sdk#5281,
paritytech/polkadot-sdk#5273) and a proper fix
(paritytech/polkadot-sdk#5234) are in the works,
but should be tested again.

I expect the chances that the system-chains run into this scenario to be
low, but it does not look like activity is so high that the inclusion of
reclaim is urgent.

---------

Co-authored-by: Bastian Köcher <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PoV reclaim underestimates proof size
8 participants