Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Do not return empty entries from state_queryStorage #2906

Merged
merged 3 commits into from
Jun 19, 2019

Conversation

svyatonik
Copy link
Contributor

closes #2826

The first problem occurs when CT are disabled. The result of state_queryStorage includes entries for every block in the range, even though changes are empty:

{"jsonrpc":"2.0","result":[{"block":"0x610c","changes":[["0x05","0x05"],["0x0a","0x0a"]]}, {"block":"0x81..8d","changes":[]}],"id":1}

I've added a check for that && now entry is only included when changes field is not empty.

The second problem is linked to CT + fake changes (see #2865 ). When there's fake change, it is shown in changes => redundant entry appears.

{"jsonrpc":"2.0","result":[{"block":"0x61..0c","changes":[["0x05","0x05"]]}, {"block":"0x81..8d","changes":[["0x05","0x05"]]}],"id":1}

I've fixed that by adding a check that prev_value != new_value.

{"jsonrpc":"2.0","result":[{"block":"0x61..0c","changes":[["0x05","0x05"]]}, {"block":"0x81..8d","changes":[["0x05","0x06"]]}],"id":1}

So after this PR, every entry in resulting Vec is guaranteed to be inserted only when requested key(s) has actually been changed at linked block.

@svyatonik svyatonik added A0-please_review Pull request needs code review. M6-rpcapi labels Jun 19, 2019
@svyatonik svyatonik requested a review from tomusdrw June 19, 2019 11:41
last_values.insert(key.clone(), data);
}

// always insert entry for the first block, because we're claiming to provide values 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.

The RPC method description claims that "This first returned result contains the initial state of storage for all keys.". But actually the first entry won't have a value for the key if the value is None:

{"jsonrpc":"2.0","result":[{"block":"0x61..0c","changes":[]}],"id":1}

But if later the key has been changed to Some(_) and then back to None, the changes will look like that (mind null in the last block' changes):

{"jsonrpc":"2.0","result":[{"block":"0x61..0c","changes":[]},{"block":"0x81..8d","changes":[["0x05","0x06"]]},{"block":"0x91..9e","changes":[["0x05",null]]}],"id":1}

So we are using both absence-of-key and null to mark None values. What do you think - does it worth to use only null for that? If so, I could revert last commit, that itself reverts this fix.

Copy link
Contributor

Choose a reason for hiding this comment

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

It might be a bit confusing but it seems fine for me. The alternative would be to print out all the keys with null value in the initial block, right?
While we could do that if user subscribes to specific keys (still a bit wasteful), it would not be feasible in case of a wildcard.

I'm fine with both, maybe let's hear @jacogr's opinion on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The alternative would be to print out all the keys with null value in the initial block, right?

Exactly

Copy link
Contributor

Choose a reason for hiding this comment

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

Prefer consistency, so always showing "something" - currently on the middleware side we have to handle both undefined and null - either way, as long as the order is correct, should not break anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, so it'll be null everywhere (speaking of this method only, of course)

Copy link
Contributor

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

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

lgtm!

last_values.insert(key.clone(), data);
}

// always insert entry for the first block, because we're claiming to provide values of
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be a bit confusing but it seems fine for me. The alternative would be to print out all the keys with null value in the initial block, right?
While we could do that if user subscribes to specific keys (still a bit wasteful), it would not be feasible in case of a wildcard.

I'm fine with both, maybe let's hear @jacogr's opinion on this.

@@ -298,17 +304,24 @@ impl<B, E, Block: BlockT, RA> State<B, E, Block, RA> where
let mut changes_map: BTreeMap<NumberFor<Block>, StorageChangeSet<Block::Hash>> = BTreeMap::new();
for key in keys {
let mut last_block = None;
for (block, _) in self.client.key_changes(begin, end, key)? {
let mut last_value = last_values.get(key).cloned().unwrap_or_default();
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have to clone here? Can't we compare with value_at_block.as_ref()?

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 is also used as storage for the last value (it is updated in the loop). I could use the same last_values map for this, but it is single clone() call vs multiple HashMap::get() + HashMap::insert() calls. Could change that if you feel this is better.

@bkchr bkchr merged commit 36c594d into master Jun 19, 2019
@bkchr bkchr deleted the fix_empty_changes_in_state_queryStorage branch June 19, 2019 13:31
MTDK1 pushed a commit to bdevux/substrate that referenced this pull request Jul 10, 2019
* do not return empty entries from state_queryStorage

* revert back None -> null change

* Revert "revert back None -> null change"

This reverts commit 318eb04.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

state_queryStorage is too verbose
5 participants