Skip to content

Commit

Permalink
Remove unwrap() in runtime_lock (#2764)
Browse files Browse the repository at this point in the history
Fix #2763

This PR gives a proper error type to the `state_trie_root_hash` function
(which retrieves the state trie root hash of a block from the network),
and makes `runtime_lock` properly propagates the error instead of
unwrapping.
  • Loading branch information
tomaka authored Sep 20, 2022
1 parent 405c38c commit 58c56ed
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 16 deletions.
51 changes: 39 additions & 12 deletions bin/light-base/src/json_rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,11 @@ struct Cache {
/// trie root hash multiple, we store these hashes in this LRU cache.
block_state_root_hashes_numbers: lru::LruCache<
[u8; 32],
future::MaybeDone<future::Shared<future::BoxFuture<'static, Result<([u8; 32], u64), ()>>>>,
future::MaybeDone<
future::Shared<
future::BoxFuture<'static, Result<([u8; 32], u64), StateTrieRootHashError>>,
>,
>,
fnv::FnvBuildHasher,
>,
}
Expand Down Expand Up @@ -1206,8 +1210,10 @@ impl<TPlat: Platform> Background<TPlat> {

/// Obtain the state trie root hash and number of the given block, and make sure to put it
/// in cache.
// TODO: better error return type
async fn state_trie_root_hash(&self, hash: &[u8; 32]) -> Result<([u8; 32], u64), ()> {
async fn state_trie_root_hash(
&self,
hash: &[u8; 32],
) -> Result<([u8; 32], u64), StateTrieRootHashError> {
let fetch = {
// Try to find an existing entry in cache, and if not create one.
let mut cache_lock = self.cache.lock().await;
Expand All @@ -1219,7 +1225,7 @@ impl<TPlat: Platform> Background<TPlat> {
.map(|h| header::decode(h, self.sync_service.block_number_bytes()))
{
Some(Ok(header)) => return Ok((*header.state_root, header.number)),
Some(Err(_)) => return Err(()),
Some(Err(err)) => return Err(StateTrieRootHashError::HeaderDecodeError(err)), // TODO: can this actually happen? unclear
None => {}
}

Expand All @@ -1228,8 +1234,14 @@ impl<TPlat: Platform> Background<TPlat> {
Some(future::MaybeDone::Done(Ok(val))) => return Ok(*val),
Some(future::MaybeDone::Future(f)) => f.clone(),
Some(future::MaybeDone::Gone) => unreachable!(), // We never use `Gone`.
Some(future::MaybeDone::Done(Err(()))) | None => {
// TODO: filter by error ^ ; invalid header for example should be returned immediately
Some(future::MaybeDone::Done(Err(
err @ StateTrieRootHashError::HeaderDecodeError(_),
))) => {
// In case of a fatal error, return immediately.
return Err(err.clone());
}
Some(future::MaybeDone::Done(Err(StateTrieRootHashError::NetworkQueryError)))
| None => {
// No existing cache entry. Create the future that will perform the fetch
// but do not actually start doing anything now.
let fetch = {
Expand Down Expand Up @@ -1266,7 +1278,8 @@ impl<TPlat: Platform> Background<TPlat> {
.unwrap();
Ok((*decoded.state_root, decoded.number))
} else {
Err(())
// TODO: better error details?
Err(StateTrieRootHashError::NetworkQueryError)
}
}
};
Expand Down Expand Up @@ -1297,7 +1310,7 @@ impl<TPlat: Platform> Background<TPlat> {
let (state_trie_root_hash, block_number) = self
.state_trie_root_hash(&hash)
.await
.map_err(|()| StorageQueryError::FindStorageRootHashError)?;
.map_err(StorageQueryError::FindStorageRootHashError)?;

let result = self
.sync_service
Expand Down Expand Up @@ -1350,8 +1363,10 @@ impl<TPlat: Platform> Background<TPlat> {

// In order to grab the runtime code and perform the call network request, we need
// to know the state trie root hash and the height of the block.
let (state_trie_root_hash, block_number) =
self.state_trie_root_hash(block_hash).await.unwrap(); // TODO: don't unwrap
let (state_trie_root_hash, block_number) = self
.state_trie_root_hash(block_hash)
.await
.map_err(RuntimeCallError::FindStorageRootHashError)?;

// Download the runtime of this block. This takes a long time as the runtime is rather
// big (around 1MiB in general).
Expand Down Expand Up @@ -1485,8 +1500,8 @@ impl<TPlat: Platform> Background<TPlat> {
#[derive(Debug, derive_more::Display)]
enum StorageQueryError {
/// Error while finding the storage root hash of the requested block.
#[display(fmt = "Unknown block")]
FindStorageRootHashError,
#[display(fmt = "Failed to obtain block state trie root: {}", _0)]
FindStorageRootHashError(StateTrieRootHashError),
/// Error while retrieving the storage item from other nodes.
#[display(fmt = "{}", _0)]
StorageRetrieval(sync_service::StorageQueryError),
Expand All @@ -1495,8 +1510,20 @@ enum StorageQueryError {
// TODO: doc and properly derive Display
#[derive(Debug, derive_more::Display, Clone)]
enum RuntimeCallError {
/// Error while finding the storage root hash of the requested block.
#[display(fmt = "Failed to obtain block state trie root: {}", _0)]
FindStorageRootHashError(StateTrieRootHashError),
Call(runtime_service::RuntimeCallError),
StartError(host::StartErr),
ReadOnlyRuntime(read_only_runtime_host::ErrorDetail),
NextKeyForbidden,
}

/// Error potentially returned by [`Background::state_trie_root_hash`].
#[derive(Debug, derive_more::Display, Clone)]
enum StateTrieRootHashError {
/// Failed to decode block header.
HeaderDecodeError(header::Error),
/// Error while fetching block header from network.
NetworkQueryError,
}
8 changes: 4 additions & 4 deletions bin/light-base/src/json_rpc_service/state_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,15 +960,15 @@ impl<TPlat: Platform> Background<TPlat> {
// This is necessary to perform network storage queries.
let (state_root, block_number) = match self.state_trie_root_hash(&hash).await {
Ok(v) => v,
Err(()) => {
Err(err) => {
self.requests_subscriptions
.respond(
&state_machine_request_id,
json_rpc::parse::build_error_response(
request_id,
json_rpc::parse::ErrorResponse::ServerError(
-32000,
&"Failed to fetch block information",
&format!("Failed to fetch block information: {}", err),
),
None,
),
Expand Down Expand Up @@ -1031,15 +1031,15 @@ impl<TPlat: Platform> Background<TPlat> {
// This is necessary to perform network storage queries.
let (state_root, block_number) = match self.state_trie_root_hash(&hash).await {
Ok(v) => v,
Err(()) => {
Err(err) => {
self.requests_subscriptions
.respond(
&state_machine_request_id,
json_rpc::parse::build_error_response(
request_id,
json_rpc::parse::ErrorResponse::ServerError(
-32000,
&"Failed to fetch block information",
&format!("Failed to fetch block information: {}", err),
),
None,
),
Expand Down
1 change: 1 addition & 0 deletions bin/wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Fixed

- Fix potential infinite loop in networking connection task. ([#2751](https://github.com/paritytech/smoldot/pull/2751))
- Fix panic when trying to perform a runtime call on an old block while having no networking connection. ([#2764](https://github.com/paritytech/smoldot/pull/2764))

### Changed

Expand Down

0 comments on commit 58c56ed

Please sign in to comment.