Bugfix: trimmed metadata hash comparison fails in is_codegen_valid_for
#1301
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #1286
What is the bug:
Metadata can be trimmed with
Metadata::retain(..)
. This is done by the CLI tool, e.g.subxt metadata --url wss://rpc.polkadot.io --pallets "ElectionProviderMultiPhase,System"
retains only the specified pallets.When comparing the hash of trimmed metadata (metadata that contains only a limited number of pallets/runtime apis) with the hash of the original metadata using the hashers
only_these_pallets
/only_these_runtime_apis
, the hashes were different. This comparison was made in the generatedis_codegen_valid_for
function.Reason for the bug
in
Metadata::retain(..)
3 things happen:retain_pallets_in_runtime_outer_types()
.The last point is what caused the bug:
When specifying
only_these_pallets
for a MetadataHasher, the variant types of the top level enums (call, event and error) were modified to discard unneded pallets before the hash is calculated. HOWEVER the same types can be included in other places of the metadata. In @niklasad1 case for the staking-miner, the"Events"
storage entry of the"System"
pallet, had a type ofVec<Event>
, whereEvent
is the event top level type. But we did not go through all types of the metadata checking for each one if they are a top level variant and modifying it accordingly before computing its hash.==> This caused the bug.
Solution
To solve the bug, the hash computation of the top level enums has been moved to the top of the
MetadataHasher::hash(..)
function. Also we explicitly insert the hash of the modified enums into a cache that is used throughout the rest of the hashing process. So whenever we encounter a type again, that is a top level enum, it is already present in the cache with the correct value.Alternative solution (not implemented)
We could also just clone and trim the metadata when calling
MetadataHasher::hash()
and specific pallets/apis are set.This is probably less performant, but maybe in the end easier and more consistent.
Testing
Added a test to confirm this works and manually tested it for the example Niklas provided.