Skip to content

Commit

Permalink
Various small improvements to state_getKeysPaged (#776)
Browse files Browse the repository at this point in the history
* Use a SipHasher for `state_get_keys_paged`

* Better key type for `state_get_keys_paged`

* Don't unwrap when `prefix` is `None`

* PR link
  • Loading branch information
tomaka authored Jun 19, 2023
1 parent 02134d2 commit 10ca492
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 14 deletions.
2 changes: 1 addition & 1 deletion light-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ hex = { version = "0.4.3", default-features = false }
itertools = "0.10.5"
log = { version = "0.4.18", default-features = false }
lru = { version = "0.10.0", default-features = false }
rand = "0.8.5"
rand = { version = "0.8.5", default-features = false }
serde = { version = "1.0.163", default-features = false, features = ["alloc", "derive"] }
serde_json = { version = "1.0.96", default-features = false, features = ["alloc"] }
siphasher = { version = "0.3.10", default-features = false }
Expand Down
17 changes: 13 additions & 4 deletions light-base/src/json_rpc_service/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use crate::{
network_service, platform::PlatformRef, runtime_service, sync_service, transactions_service,
util,
};

use super::StartConfig;
Expand Down Expand Up @@ -215,9 +216,17 @@ struct Cache {
/// When `state_getKeysPaged` is called and the response is truncated, the response is
/// inserted in this cache. The API user is likely to call `state_getKeysPaged` again with
/// the same parameters, in which case we hit the cache and avoid the networking requests.
/// The keys are `(block_hash, prefix)` and values are list of keys.
state_get_keys_paged:
lru::LruCache<([u8; 32], Option<methods::HexString>), Vec<Vec<u8>>, fnv::FnvBuildHasher>,
/// The values are list of keys.
state_get_keys_paged: lru::LruCache<GetKeysPagedCacheKey, Vec<Vec<u8>>, util::SipHasherBuild>,
}

/// See [`Cache::state_get_keys_paged`].
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct GetKeysPagedCacheKey {
/// Value of the `hash` parameter of the call to `state_getKeysPaged`.
hash: [u8; 32],
/// Value of the `prefix` parameter of the call to `state_getKeysPaged`.
prefix: Vec<u8>,
}

pub(super) fn start<TPlat: PlatformRef>(
Expand Down Expand Up @@ -255,7 +264,7 @@ pub(super) fn start<TPlat: PlatformRef>(
),
state_get_keys_paged: lru::LruCache::with_hasher(
NonZeroUsize::new(2).unwrap(),
Default::default(),
util::SipHasherBuild::new(rand::random()),
),
}),
genesis_block_hash: config.genesis_block_hash,
Expand Down
24 changes: 15 additions & 9 deletions light-base/src/json_rpc_service/background/state_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

//! All legacy JSON-RPC method handlers that relate to the chain or the storage.

use super::{Background, PlatformRef, SubscriptionMessage};
use super::{Background, GetKeysPagedCacheKey, PlatformRef, SubscriptionMessage};

use crate::runtime_service;

Expand Down Expand Up @@ -1101,15 +1101,21 @@ impl<TPlat: PlatformRef> Background<TPlat> {
),
};

// A prefix of `None` means "empty".
let prefix = prefix.unwrap_or(methods::HexString(Vec::new())).0;

// Because the user is likely to call this function multiple times in a row with the exact
// same parameters, we store the untruncated responses in a cache. Check if we hit the
// cache.
if let Some(keys) = self
.cache
.lock()
.await
.state_get_keys_paged
.get(&(hash, prefix.clone()))
if let Some(keys) =
self.cache
.lock()
.await
.state_get_keys_paged
.get(&GetKeysPagedCacheKey {
hash,
prefix: prefix.clone(),
})
{
let out = keys
.iter()
Expand Down Expand Up @@ -1156,7 +1162,7 @@ impl<TPlat: PlatformRef> Background<TPlat> {
.storage_prefix_keys_query(
block_number,
&hash,
&prefix.as_ref().unwrap().0, // TODO: don't unwrap! what is this Option?
&prefix,
&state_root,
3,
Duration::from_secs(12),
Expand All @@ -1183,7 +1189,7 @@ impl<TPlat: PlatformRef> Background<TPlat> {
.lock()
.await
.state_get_keys_paged
.push((hash, prefix), keys);
.push(GetKeysPagedCacheKey { hash, prefix }, keys);
}

methods::Response::state_getKeysPaged(out).to_json_response(request_id.0)
Expand Down
1 change: 1 addition & 0 deletions wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Fix panic when the `ext_default_child_storage_clear_prefix_version_1` and `ext_default_child_storage_clear_prefix_version_2` functions are called. ([#764](https://github.com/smol-dot/smoldot/pull/764))
- Fix wrong trie root hash calculation with `state_version = 1`. ([#711](https://github.com/smol-dot/smoldot/pull/711))
- Fix bug when decoding BABE configuration produced by runtimes using version 1 of the `BabeApi` API. In practice, this should concern only old Kusama blocks. ([#739](https://github.com/smol-dot/smoldot/pull/739))
- No longer panic when `state_getKeysPaged` is called with a `prefix` parameter equal to `null`. ([#776](https://github.com/smol-dot/smoldot/pull/776))

## 1.0.9 - 2023-06-08

Expand Down

0 comments on commit 10ca492

Please sign in to comment.