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

(rpc_server): Add block_height_checker and Fix Chunk Fetch Bug #359

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading