Skip to content

Commit 3a2f8d2

Browse files
committed
fix to calculate state size
1 parent 17db12a commit 3a2f8d2

File tree

7 files changed

+82
-15
lines changed

7 files changed

+82
-15
lines changed

database/src/base/rpc_server.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ pub trait ReaderDbManager {
9393
method_name: &str,
9494
) -> anyhow::Result<readnode_primitives::QueryData<Vec<u8>>>;
9595

96+
// Returns the contract code size at the given block height
97+
async fn get_contract_code_size(
98+
&self,
99+
account_id: &near_primitives::types::AccountId,
100+
request_block_height: near_primitives::types::BlockHeight,
101+
method_name: &str,
102+
) -> anyhow::Result<u64>;
103+
96104
/// Returns the near_primitives::account::AccessKey at the given block height
97105
async fn get_access_key(
98106
&self,

database/src/postgres/rpc_server.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,37 @@ impl crate::ReaderDbManager for crate::PostgresDBManager {
357357
})
358358
}
359359

360+
async fn get_contract_code_size(
361+
&self,
362+
account_id: &near_primitives::types::AccountId,
363+
request_block_height: near_primitives::types::BlockHeight,
364+
method_name: &str,
365+
) -> anyhow::Result<u64> {
366+
let shard_id_pool = self.get_shard_connection(account_id).await?;
367+
crate::metrics::SHARD_DATABASE_READ_QUERIES
368+
.with_label_values(&[
369+
&shard_id_pool.shard_id.to_string(),
370+
method_name,
371+
"state_changes_contract",
372+
])
373+
.inc();
374+
let (code_size,): (bigdecimal::BigDecimal,) = sqlx::query_as(
375+
"
376+
SELECT pg_column_size(data_value)
377+
FROM state_changes_contract
378+
WHERE account_id = $1
379+
AND block_height <= $2
380+
ORDER BY block_height DESC
381+
LIMIT 1;
382+
",
383+
)
384+
.bind(account_id.to_string())
385+
.bind(bigdecimal::BigDecimal::from(request_block_height))
386+
.fetch_one(shard_id_pool.pool)
387+
.await?;
388+
Ok(code_size.to_u64().map(|size| size).unwrap_or_default())
389+
}
390+
360391
async fn get_access_key(
361392
&self,
362393
account_id: &near_primitives::types::AccountId,

rpc-server/src/config.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ impl ServerContext {
153153

154154
let compiled_contract_code_cache =
155155
std::sync::Arc::new(CompiledCodeCache::new(contract_code_cache_size_in_bytes));
156-
156+
157+
crate::metrics::CARGO_PKG_VERSION
158+
.with_label_values(&[NEARD_VERSION])
159+
.inc();
160+
157161
Ok(Self {
158162
s3_client,
159163
db_manager: std::sync::Arc::new(Box::new(db_manager)),

rpc-server/src/metrics.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use actix_web::{get, Responder};
2-
use prometheus::{Encoder, IntCounterVec, IntGauge, IntGaugeVec, Opts};
2+
use prometheus::{CounterVec, Encoder, IntCounterVec, IntGauge, IntGaugeVec, Opts};
33

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

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

116+
pub(crate) static ref CARGO_PKG_VERSION: CounterVec = {
117+
let opts = Opts::new("cargo_pkg_version", "Cargo package version. This is used to track the version of the running server.")
118+
.variable_label("version");
119+
let counter_vec = CounterVec::new(opts, &["version"]).expect("metric can be created");
120+
prometheus::register(Box::new(counter_vec.clone())).unwrap();
121+
counter_vec
122+
};
123+
116124
pub(crate) static ref LEGACY_DATABASE_TX_DETAILS: IntCounterVec = register_int_counter_vec(
117125
"legacy_database_tx_details",
118126
"Total number of calls to the legacy database for transaction details",

rpc-server/src/modules/blocks/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -335,10 +335,6 @@ impl BlocksInfoByFinality {
335335
// Update final block info in the cache.
336336
// Executes every second.
337337
pub async fn update_final_block(&self, block_info: BlockInfo) {
338-
tracing::debug!(
339-
"Update final block info: {:?}",
340-
block_info.block_cache.block_height
341-
);
342338
let mut final_block_lock = self.final_block.write().await;
343339
final_block_lock.block_cache = block_info.block_cache;
344340
final_block_lock.block_view = block_info.block_view;
@@ -348,11 +344,6 @@ impl BlocksInfoByFinality {
348344
// Update optimistic block changes and optimistic block info in the cache.
349345
// Executes every second.
350346
pub async fn update_optimistic_block(&self, block_info: BlockInfo) {
351-
tracing::debug!(
352-
"Update optimistic block info: {:?}",
353-
block_info.block_cache.block_height
354-
);
355-
356347
let mut optimistic_changes_lock = self.optimistic_changes.write().await;
357348
optimistic_changes_lock.account_changes = block_info.changes_in_block_account_map().await;
358349

rpc-server/src/modules/queries/contract_runner/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use std::collections::HashMap;
22

3-
use near_vm_runner::ContractRuntimeCache;
4-
53
use crate::modules::blocks::BlocksInfoByFinality;
64
use code_storage::CodeStorage;
5+
use near_vm_runner::ContractRuntimeCache;
76

87
mod code_storage;
98

@@ -143,14 +142,30 @@ pub async fn run_contract(
143142
}
144143
};
145144

145+
// We need to calculate the state size of the contract to determine if we should prefetch the state or not.
146+
// The state size is the storage usage minus the code size.
147+
// If the state size is less than the prefetch_state_size_limit, we prefetch the state.
148+
let code_size = if let Some(contract_code) = &contract_code.contract_code {
149+
size_of_val(&contract_code.code()) as u64
150+
} else {
151+
if let Some(code) = contract_code_cache.get(&code_hash).await {
152+
size_of_val(&code) as u64
153+
} else {
154+
db_manager
155+
.get_contract_code_size(account_id, block.block_height, "query_call_function")
156+
.await
157+
.unwrap_or(0)
158+
}
159+
};
160+
let state_size = contract.data.storage_usage() - code_size;
146161
// Init an external database interface for the Runtime logic
147162
let code_storage = CodeStorage::init(
148163
db_manager.clone(),
149164
account_id.clone(),
150165
block.block_height,
151166
validators,
152167
optimistic_data,
153-
contract.data.storage_usage() <= prefetch_state_size_limit,
168+
state_size <= prefetch_state_size_limit,
154169
)
155170
.await;
156171

rpc-server/src/modules/queries/methods.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,17 @@ async fn view_state(
443443
block_hash: block.block_hash,
444444
},
445445
)?;
446-
if prefix.is_empty() && account.data.storage_usage() > data.prefetch_state_size_limit {
446+
447+
// Calculate the state size excluding the contract code size to check if it's too large to fetch.
448+
// The state size is the storage usage minus the code size.
449+
let contract_code_size = data
450+
.db_manager
451+
.get_contract_code_size(account_id, block.block_height, "query_call_function")
452+
.await
453+
.unwrap_or(0);
454+
let state_size = account.data.storage_usage() - contract_code_size;
455+
// If the prefix is empty and the state size is larger than the limit, return an error.
456+
if prefix.is_empty() && state_size > data.prefetch_state_size_limit {
447457
return Err(
448458
near_jsonrpc::primitives::types::query::RpcQueryError::TooLargeContractState {
449459
contract_account_id: account_id.clone(),

0 commit comments

Comments
 (0)