Skip to content

Commit

Permalink
(rpc_server): Add block_height_checker and Fix Chunk Fetch Bug (#359)
Browse files Browse the repository at this point in the history
* add block_height_cheker to avoid trying fetch not existing blocks

* clippy
  • Loading branch information
kobayurii authored Oct 7, 2024
1 parent 168622d commit cdc1f51
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 35 deletions.
97 changes: 63 additions & 34 deletions rpc-server/src/modules/blocks/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use near_primitives::views::StateChangeValueView;

use crate::config::ServerContext;
use crate::modules::blocks::utils::{
fetch_block_from_cache_or_get, fetch_chunk_from_s3, is_matching_change,
check_block_height, fetch_block_from_cache_or_get, fetch_chunk_from_s3, is_matching_change,
};

/// `block` rpc method implementation
Expand Down Expand Up @@ -288,7 +288,10 @@ pub async fn fetch_block(
tracing::debug!("`fetch_block` call");
let block_height = match block_reference {
near_primitives::types::BlockReference::BlockId(block_id) => match block_id {
near_primitives::types::BlockId::Height(block_height) => Ok(*block_height),
near_primitives::types::BlockId::Height(block_height) => {
check_block_height(data, *block_height).await?;
Ok(*block_height)
}
near_primitives::types::BlockId::Hash(block_hash) => {
match data
.db_manager
Expand Down Expand Up @@ -339,18 +342,36 @@ pub async fn fetch_block(
Ok(data.genesis_info.genesis_block_cache.block_height)
}
}?;
let block_view = near_lake_framework::s3_fetchers::fetch_block(
&data.s3_client,
&data.s3_bucket_name,
block_height,
)
.await
.map_err(|err| {
tracing::error!("Failed to fetch block from S3: {}", err);
near_jsonrpc::primitives::types::blocks::RpcBlockError::UnknownBlock {
error_message: format!("BLOCK HEIGHT: {:?}", block_height),
}
})?;
let block_view = if block_height
== data
.blocks_info_by_finality
.final_cache_block()
.await
.block_height
{
data.blocks_info_by_finality.final_block_view().await
} else if block_height
== data
.blocks_info_by_finality
.optimistic_cache_block()
.await
.block_height
{
data.blocks_info_by_finality.optimistic_block_view().await
} else {
near_lake_framework::s3_fetchers::fetch_block(
&data.s3_client,
&data.s3_bucket_name,
block_height,
)
.await
.map_err(|err| {
tracing::error!("Failed to fetch block from S3: {}", err);
near_jsonrpc::primitives::types::blocks::RpcBlockError::UnknownBlock {
error_message: format!("BLOCK HEIGHT: {:?}", block_height),
}
})?
};
Ok(near_jsonrpc::primitives::types::blocks::RpcBlockResponse { block_view })
}

Expand All @@ -366,31 +387,39 @@ pub async fn fetch_chunk(
near_jsonrpc::primitives::types::chunks::ChunkReference::BlockShardId {
block_id,
shard_id,
} => match block_id {
near_primitives::types::BlockId::Height(block_height) => data
.db_manager
.get_block_by_height_and_shard_id(block_height, shard_id, "chunk")
.await
.map_err(|_err| {
near_jsonrpc::primitives::types::chunks::RpcChunkError::InvalidShardId {
shard_id,
}
})
.map(|block_height_shard_id| (block_height_shard_id.0, block_height_shard_id.1))?,
near_primitives::types::BlockId::Hash(block_hash) => {
let block_height = data
.db_manager
.get_block_height_by_hash(block_hash, "chunk")
.await
.map_err(|err| {
tracing::error!("Failed to fetch block by hash: {}", err);
} => {
let block_height =
match block_id {
near_primitives::types::BlockId::Height(block_height) => {
check_block_height(data, block_height).await.map_err(|err| {
near_jsonrpc::primitives::types::chunks::RpcChunkError::UnknownBlock {
error_message: format!("BLOCK: {:?}", block_hash),
error_message: err.to_string(),
}
})?;
block_height
}
near_primitives::types::BlockId::Hash(block_hash) => data
.db_manager
.get_block_height_by_hash(block_hash, "chunk")
.await
.map_err(|err| {
tracing::error!("Failed to fetch block by hash: {}", err);
near_jsonrpc::primitives::types::chunks::RpcChunkError::UnknownBlock {
error_message: format!("BLOCK: {:?}", block_hash),
}
})?,
};
// Check if the chunk stored in block with the given height
if let Ok(block_height_shard_id) = data
.db_manager
.get_block_by_height_and_shard_id(block_height, shard_id, "chunk")
.await
{
(block_height_shard_id.0, block_height_shard_id.1)
} else {
(block_height, shard_id)
}
},
}
near_jsonrpc::primitives::types::chunks::ChunkReference::ChunkHash { chunk_id } => data
.db_manager
.get_block_by_chunk_hash(chunk_id, "chunk")
Expand Down
42 changes: 41 additions & 1 deletion rpc-server/src/modules/blocks/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@ use crate::config::ServerContext;
use crate::modules::blocks::methods::fetch_block;
use crate::modules::blocks::CacheBlock;

// Helper function to check if the requested block height is within the range of the available blocks
// If block height is lower than genesis block height, return an error block height is too low
// If block height is higher than optimistic block height, return an error block height is too high
// Otherwise return Ok(())
pub async fn check_block_height(
data: &actix_web::web::Data<ServerContext>,
block_height: near_primitives::types::BlockHeight,
) -> Result<(), near_jsonrpc::primitives::types::blocks::RpcBlockError> {
let optimistic_block_height = data
.blocks_info_by_finality
.optimistic_cache_block()
.await
.block_height;
let genesis_block_height = data.genesis_info.genesis_block_cache.block_height;
if block_height < genesis_block_height {
return Err(
near_jsonrpc::primitives::types::blocks::RpcBlockError::UnknownBlock {
error_message: format!(
"Requested block height {} is to low, genesis block height is {}",
block_height, genesis_block_height
),
},
);
}
if block_height > optimistic_block_height {
return Err(
near_jsonrpc::primitives::types::blocks::RpcBlockError::UnknownBlock {
error_message: format!(
"Requested block height {} is to high, optimistic block height is {}",
block_height, optimistic_block_height
),
},
);
}
Ok(())
}

#[cfg_attr(
feature = "tracing-instrumentation",
tracing::instrument(skip(s3_client))
Expand Down Expand Up @@ -85,7 +122,10 @@ pub async fn fetch_block_from_cache_or_get(
let block = match block_reference {
near_primitives::types::BlockReference::BlockId(block_id) => {
let block_height = match block_id {
near_primitives::types::BlockId::Height(block_height) => *block_height,
near_primitives::types::BlockId::Height(block_height) => {
check_block_height(data, *block_height).await?;
*block_height
}
near_primitives::types::BlockId::Hash(hash) => data
.db_manager
.get_block_height_by_hash(*hash, method_name)
Expand Down

0 comments on commit cdc1f51

Please sign in to comment.