Skip to content

Commit c370570

Browse files
committed
paginated state optimization
1 parent 1bcc8c6 commit c370570

File tree

3 files changed

+59
-20
lines changed

3 files changed

+59
-20
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ async fn optimistic_view_state(
566566
}
567567

568568
#[cfg_attr(feature = "tracing-instrumentation", tracing::instrument(skip(data)))]
569-
async fn database_view_state(
569+
pub async fn database_view_state(
570570
data: &Data<ServerContext>,
571571
block: &near_primitives::views::BlockView,
572572
account_id: &near_primitives::types::AccountId,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ pub async fn view_state_paginated(
1818
fetch_block_from_cache_or_get(&data, &block_reference, "view_state_paginated").await?;
1919

2020
let state_values = get_state_from_db_paginated(
21-
&data.db_manager,
21+
&data,
2222
&request_data.account_id,
23-
block.header.height,
23+
&block,
2424
request_data.next_page_token,
2525
)
2626
.await?;
Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,76 @@
1-
#[cfg_attr(
2-
feature = "tracing-instrumentation",
3-
tracing::instrument(skip(db_manager))
4-
)]
1+
use crate::{config::ServerContext, modules::queries::methods::database_view_state};
2+
use actix_web::web::Data;
3+
4+
#[cfg_attr(feature = "tracing-instrumentation", tracing::instrument(skip(data)))]
55
pub async fn get_state_from_db_paginated(
6-
db_manager: &std::sync::Arc<Box<dyn database::ReaderDbManager + Sync + Send + 'static>>,
6+
data: &Data<ServerContext>,
77
account_id: &near_primitives::types::AccountId,
8-
block_height: near_primitives::types::BlockHeight,
8+
block: &near_primitives::views::BlockView,
99
page_token: database::PageToken,
1010
) -> Result<crate::modules::state::PageStateValues, near_jsonrpc::primitives::errors::RpcError> {
1111
tracing::debug!(
1212
"`get_state_from_db_paginated` call. AccountId {}, block {}, page_token {:?}",
1313
account_id,
14-
block_height,
14+
block.header.height,
1515
page_token,
1616
);
1717

18-
let (values, next_page_token) = db_manager
19-
.get_state_by_page(account_id, block_height, page_token, "view_state_paginated")
18+
let account = data
19+
.db_manager
20+
.get_account(account_id, block.header.height, "query_view_state")
21+
.await
22+
.map_err(
23+
|_err| near_jsonrpc::primitives::types::query::RpcQueryError::UnknownAccount {
24+
requested_account_id: account_id.clone(),
25+
block_height: block.header.height,
26+
block_hash: block.header.hash,
27+
},
28+
)?;
29+
30+
// Calculate the state size excluding the contract code size to check if it's too large to fetch.
31+
// The state size is the storage usage minus the code size.
32+
// more details: nearcore/runtime/runtime/src/state_viewer/mod.rs:150
33+
let code_len = data
34+
.db_manager
35+
.get_contract_code(account_id, block.header.height, "query_view_state")
2036
.await
21-
.map_err(|err| {
22-
near_jsonrpc::primitives::errors::RpcError::new_internal_error(
23-
Some(serde_json::Value::String(err.to_string())),
24-
"Failed to get page state from DB. Please try again!".to_string(),
37+
.map(|code| code.data.len() as u64)
38+
.unwrap_or_default();
39+
40+
let state_size = account.data.storage_usage().saturating_sub(code_len);
41+
let (values, next_page_token) = if state_size <= 1_000_000 {
42+
let values = database_view_state(data, block, account_id, &[]).await?;
43+
(values, None)
44+
} else {
45+
// If the state size is too large, we try to fetch the state in pages.
46+
// This is a fallback mechanism to avoid fetching too much data at once.
47+
let (raw_values, next_page_token) = data
48+
.db_manager
49+
.get_state_by_page(
50+
account_id,
51+
block.header.height,
52+
database::PageToken::default(),
53+
"view_state_paginated",
2554
)
26-
})?;
27-
Ok(crate::modules::state::PageStateValues {
28-
values: values
55+
.await
56+
.map_err(|err| {
57+
near_jsonrpc::primitives::errors::RpcError::new_internal_error(
58+
Some(serde_json::Value::String(err.to_string())),
59+
"Failed to get page state from DB. Please try again!".to_string(),
60+
)
61+
})?;
62+
let values = raw_values
2963
.into_iter()
3064
.map(|(k, v)| near_primitives::views::StateItem {
3165
key: k.into(),
3266
value: v.into(),
3367
})
34-
.collect(),
68+
.collect();
69+
(values, next_page_token)
70+
};
71+
72+
Ok(crate::modules::state::PageStateValues {
73+
values,
3574
next_page_token,
3675
})
3776
}

0 commit comments

Comments
 (0)