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

Empty tuple is encoded as null #4146

Closed
ntn-x2 opened this issue Nov 2, 2021 · 5 comments
Closed

Empty tuple is encoded as null #4146

ntn-x2 opened this issue Nov 2, 2021 · 5 comments
Labels

Comments

@ntn-x2
Copy link

ntn-x2 commented Nov 2, 2021

After upgrading our parachain to use metadata v14, we now have no way to distinguish whether an element is present or not in a StorageMap<AccountId32 ()>, as the api.query.pallet.storage(key) returns null in both cases. I can see also from polkadotjs apps that the map is a map from AccountId32 to Option<Null>.
So far, the only workaround I found is to fetch ALL the keys via api.query.pallet.keys and then filter, but that can get quite expensive if the map has a lot of keys. Is there a more efficient way to check for existence in such a map or, if there is not, would it be possible to fix this issue by encoding empty tuples differently? I am not sure if this issue pertains the SDK side or the chain side.

I also opened an issue in the scale-info repo.

@jacogr
Copy link
Member

jacogr commented Nov 2, 2021

The API will, when the storage key from the node returns null, apply the fallback as specified in the metadata. The fallback is generally the Default value for that type.

() has the same encoding as Null on the JS side (empty bytes), so () is treated as an alias for Null (since it has nothing inside it).

@ntn-x2
Copy link
Author

ntn-x2 commented Nov 2, 2021

Ok so there is no efficient way to understand whether a key exists in a given map or not? Assuming the default encoding is maintained.

@jacogr jacogr added the support label Nov 2, 2021
@ntn-x2
Copy link
Author

ntn-x2 commented Nov 4, 2021

Ok I have found a workaround using raw keys that avoids the automatic encoding of () to Null.

  // Compute the raw key for the given storage element
  const rawKey = await api.query.pallet.storage.key(input)
  // Fetch the raw storage entry using the computed key
  const encodedStorageValue = await api.rpc.state.queryStorageAt<Codec[]>([rawKey])
  // Checks the retrieved encoding to check whether the value is actually present or not
  const isPresent = encodedStorageValue.pop()!.toU8a()[0] === 1

It might not be very beautiful, but it does what it needs to do without requiring to fetch the whole storage content and then filtering afterwards. I am still open to suggestions to make this better, but I also think this might help other people in the same situation.

@jacogr
Copy link
Member

jacogr commented Nov 8, 2021

Closing.

@jacogr jacogr closed this as completed Nov 8, 2021
@polkadot-js-bot
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.

@polkadot-js polkadot-js locked as resolved and limited conversation to collaborators Nov 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants