Skip to content

Commit

Permalink
Corrected state size calculation logic (#371)
Browse files Browse the repository at this point in the history
* fix to calculate state size

* clippy

* fix calculate state size limit

* changelog
  • Loading branch information
kobayurii committed Nov 25, 2024
1 parent a82b8d5 commit 595b025
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 14 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/near/read-rpc/compare/main...develop)

### What's Changed
* Corrected state size calculation logic.
* Integrated cargo_pkg_version metric to reflect the current server version.
* Delete unnecessary debug logs about update blocks by finalities

## [0.3.1](https://github.com/near/read-rpc/releases/tag/v0.3.1)

### Supported Nearcore Version
- nearcore v2.3.0
- rust v1.81.0

### What's Changed
* Improved bulk insertion of state_changes, reducing database requests from hundreds to a maximum of 7 per block.
* Configuration improvement. Create default config.toml on start application to loaded parameters from the environment variables.
Expand Down
4 changes: 4 additions & 0 deletions rpc-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ impl ServerContext {
let compiled_contract_code_cache =
std::sync::Arc::new(CompiledCodeCache::new(contract_code_cache_size_in_bytes));

crate::metrics::CARGO_PKG_VERSION
.with_label_values(&[NEARD_VERSION])
.inc();

Ok(Self {
s3_client,
db_manager: std::sync::Arc::new(Box::new(db_manager)),
Expand Down
10 changes: 9 additions & 1 deletion rpc-server/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use actix_web::{get, Responder};
use prometheus::{Encoder, IntCounterVec, IntGauge, IntGaugeVec, Opts};
use prometheus::{CounterVec, Encoder, IntCounterVec, IntGauge, IntGaugeVec, Opts};

type Result<T, E> = std::result::Result<T, E>;

Expand Down Expand Up @@ -113,6 +113,14 @@ lazy_static! {
"Optimistic updating status. 0: working, 1: not working",
).unwrap();

pub(crate) static ref CARGO_PKG_VERSION: CounterVec = {
let opts = Opts::new("cargo_pkg_version", "Cargo package version. This is used to track the version of the running server.")
.variable_label("version");
let counter_vec = CounterVec::new(opts, &["version"]).expect("metric can be created");
prometheus::register(Box::new(counter_vec.clone())).unwrap();
counter_vec
};

pub(crate) static ref LEGACY_DATABASE_TX_DETAILS: IntCounterVec = register_int_counter_vec(
"legacy_database_tx_details",
"Total number of calls to the legacy database for transaction details",
Expand Down
9 changes: 0 additions & 9 deletions rpc-server/src/modules/blocks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,6 @@ impl BlocksInfoByFinality {
// Update final block info in the cache.
// Executes every second.
pub async fn update_final_block(&self, block_info: BlockInfo) {
tracing::debug!(
"Update final block info: {:?}",
block_info.block_cache.block_height
);
let mut final_block_lock = self.final_block.write().await;
final_block_lock.block_cache = block_info.block_cache;
final_block_lock.block_view = block_info.block_view;
Expand All @@ -348,11 +344,6 @@ impl BlocksInfoByFinality {
// Update optimistic block changes and optimistic block info in the cache.
// Executes every second.
pub async fn update_optimistic_block(&self, block_info: BlockInfo) {
tracing::debug!(
"Update optimistic block info: {:?}",
block_info.block_cache.block_height
);

let mut optimistic_changes_lock = self.optimistic_changes.write().await;
optimistic_changes_lock.account_changes = block_info.changes_in_block_account_map().await;

Expand Down
24 changes: 21 additions & 3 deletions rpc-server/src/modules/queries/contract_runner/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::collections::HashMap;

use near_vm_runner::ContractRuntimeCache;

use crate::modules::blocks::BlocksInfoByFinality;
use code_storage::CodeStorage;
use near_vm_runner::ContractRuntimeCache;

mod code_storage;

Expand Down Expand Up @@ -137,20 +136,39 @@ pub async fn run_contract(
block_hash: block.block_hash,
}
})?;
println!("Contract code len {}", code.data.len());
contract_code_cache.put(code_hash, code.data.clone()).await;
Contract::new(Some(code.data), code_hash)
}
}
};

// We need to calculate the state size of the contract to determine if we should prefetch the state or not.
// The state size is the storage usage minus the code size.
// If the state size is less than the prefetch_state_size_limit, we prefetch the state.
let code_len = if let Some(contract_code) = &contract_code.contract_code {
contract_code.code().len()
} else if let Some(code) = contract_code_cache.get(&code_hash).await {
code.len()
} else {
db_manager
.get_contract_code(account_id, block.block_height, "query_call_function")
.await
.map(|code| code.data.len())
.unwrap_or_default()
};
let state_size = contract
.data
.storage_usage()
.saturating_sub(code_len as u64);
// Init an external database interface for the Runtime logic
let code_storage = CodeStorage::init(
db_manager.clone(),
account_id.clone(),
block.block_height,
validators,
optimistic_data,
contract.data.storage_usage() <= prefetch_state_size_limit,
state_size <= prefetch_state_size_limit,
)
.await;

Expand Down
14 changes: 13 additions & 1 deletion rpc-server/src/modules/queries/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,19 @@ async fn view_state(
block_hash: block.block_hash,
},
)?;
if prefix.is_empty() && account.data.storage_usage() > data.prefetch_state_size_limit {

// Calculate the state size excluding the contract code size to check if it's too large to fetch.
// The state size is the storage usage minus the code size.
// more details: nearcore/runtime/runtime/src/state_viewer/mod.rs:150
let code_len = data
.db_manager
.get_contract_code(account_id, block.block_height, "query_view_state")
.await
.map(|code| code.data.len() as u64)
.unwrap_or_default();
let state_size = account.data.storage_usage().saturating_sub(code_len);
// If the prefix is empty and the state size is larger than the limit, return an error.
if prefix.is_empty() && state_size > data.prefetch_state_size_limit {
return Err(
near_jsonrpc::primitives::types::query::RpcQueryError::TooLargeContractState {
contract_account_id: account_id.clone(),
Expand Down

0 comments on commit 595b025

Please sign in to comment.