Skip to content

Commit b29506e

Browse files
committed
reffactoring and improvement. Add configs.
1 parent d728f10 commit b29506e

File tree

9 files changed

+209
-74
lines changed

9 files changed

+209
-74
lines changed

configuration/src/configs/general.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub struct GeneralRpcServerConfig {
2121
pub block_cache_size: f64,
2222
pub shadow_data_consistency_rate: f64,
2323
pub prefetch_state_size_limit: u64,
24+
pub available_data_ranges: u64,
25+
pub archival_mode: bool,
2426
}
2527

2628
#[derive(Debug, Clone)]
@@ -120,6 +122,14 @@ pub struct CommonGeneralRpcServerConfig {
120122
pub shadow_data_consistency_rate: Option<f64>,
121123
#[serde(deserialize_with = "deserialize_optional_data_or_env", default)]
122124
pub prefetch_state_size_limit: Option<u64>,
125+
#[validate(range(
126+
min = 1,
127+
message = "Available data ranges must be greater than or equal to 1"
128+
))]
129+
#[serde(deserialize_with = "deserialize_optional_data_or_env", default)]
130+
pub available_data_ranges: Option<u64>,
131+
#[serde(deserialize_with = "deserialize_optional_data_or_env", default)]
132+
pub archival_mode: Option<bool>,
123133
}
124134

125135
impl CommonGeneralRpcServerConfig {
@@ -146,6 +156,14 @@ impl CommonGeneralRpcServerConfig {
146156
pub fn default_prefetch_state_size_limit() -> u64 {
147157
100_000
148158
}
159+
160+
pub fn default_available_data_ranges() -> u64 {
161+
1
162+
}
163+
164+
pub fn default_archival_mode() -> bool {
165+
false
166+
}
149167
}
150168

151169
impl Default for CommonGeneralRpcServerConfig {
@@ -157,6 +175,8 @@ impl Default for CommonGeneralRpcServerConfig {
157175
block_cache_size: Some(Self::default_block_cache_size()),
158176
shadow_data_consistency_rate: Some(Self::default_shadow_data_consistency_rate()),
159177
prefetch_state_size_limit: Some(Self::default_prefetch_state_size_limit()),
178+
available_data_ranges: Some(Self::default_available_data_ranges()),
179+
archival_mode: Some(Self::default_archival_mode()),
160180
}
161181
}
162182
}
@@ -262,6 +282,14 @@ impl From<CommonGeneralConfig> for GeneralRpcServerConfig {
262282
.rpc_server
263283
.prefetch_state_size_limit
264284
.unwrap_or_else(CommonGeneralRpcServerConfig::default_prefetch_state_size_limit),
285+
available_data_ranges: common_config
286+
.rpc_server
287+
.available_data_ranges
288+
.unwrap_or_else(CommonGeneralRpcServerConfig::default_available_data_ranges),
289+
archival_mode: common_config
290+
.rpc_server
291+
.archival_mode
292+
.unwrap_or_else(CommonGeneralRpcServerConfig::default_archival_mode),
265293
}
266294
}
267295
}

configuration/src/default_env_configs.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ rpc_auth_token = "${RPC_AUTH_TOKEN}"
3030
## Default value is redis://127.0.0.1/
3131
redis_url = "${REDIS_URL}"
3232
33+
## Represents the number of available data ranges.
34+
## 1 means it will be available last 500_000 blocks (~11 epochs).
35+
## 2 means it will be available last 1_000_000 blocks (~22 epochs) etc.
36+
## Default value is 1
37+
available_data_ranges = "${AVAILABLE_DATA_RANGES}"
38+
39+
## If true, means we store whole state changes in the database
40+
## and available_data_ranges will be ignored
41+
## and genesis block_height will be used as earliest_available_block_height
42+
archival_mode = "${ARCHIVAL_MODE}"
43+
3344
### Rpc server general configuration
3445
[general.rpc_server]
3546

configuration/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use validator::Validate;
77

88
mod configs;
99
mod default_env_configs;
10+
pub mod utils;
1011

1112
pub use crate::configs::database::DatabaseConfig;
1213
pub use crate::configs::general::ChainId;

configuration/src/utils.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use near_lake_framework::near_indexer_primitives::near_primitives;
2+
3+
/// This constant represents the block height range.
4+
/// It is set to 500_000, which means that the data splits avery 500_000 blocks.
5+
pub const BLOCK_HEIGHT_RANGE: u64 = 500_000;
6+
7+
/// # Explanation of the logic:
8+
///
9+
/// 1. `block_height / 500000`
10+
///
11+
/// * This integer division truncates any remainder, effectively grouping numbers into bins of 500,000.
12+
///
13+
/// * Example: 73908345 / 500000 = 147 (as integer division discards the remainder).
14+
///
15+
/// 2. `* 5`
16+
///
17+
/// * Since each bin represents a multiple of 500,000, multiplying by 5 scales the result to match the pattern you provided.
18+
///
19+
/// # Example Calculations:
20+
/// Example 1: 73908345
21+
///
22+
/// 1. 73908345 / 500000 = 147
23+
///
24+
/// 2. 147 * 5 = 735
25+
///
26+
/// Output: 735
27+
///
28+
/// Example 2: 130501000
29+
///
30+
/// 1. 130501000 / 500000 = 261
31+
///
32+
/// 2. 261 * 5 = 1305
33+
///
34+
/// Output: 1305
35+
pub async fn get_data_range_id(
36+
block_height: &near_primitives::types::BlockHeight,
37+
) -> anyhow::Result<u64> {
38+
Ok((block_height / BLOCK_HEIGHT_RANGE) * 5)
39+
}
40+
41+
/// This function calculates the earliest available block height based on the final block height
42+
pub async fn get_earliest_available_block_height(
43+
final_block_height: u64,
44+
available_data_ranges: u64,
45+
) -> anyhow::Result<u64> {
46+
let final_range_id = get_data_range_id(&final_block_height).await?;
47+
Ok(final_range_id * 100_000 + available_data_ranges * BLOCK_HEIGHT_RANGE)
48+
}
49+
50+
/// This function checks if the block height is available in the database
51+
/// It returns an error if the block height is less than the earliest available block
52+
pub async fn check_block_height(
53+
block_height: &near_primitives::types::BlockHeight,
54+
final_block_height: &near_primitives::types::BlockHeight,
55+
available_data_ranges: u64,
56+
archival_mode: bool,
57+
) -> anyhow::Result<()> {
58+
if archival_mode {
59+
return Ok(());
60+
}
61+
let earliest_available_block =
62+
get_earliest_available_block_height(*final_block_height, available_data_ranges).await?;
63+
if *block_height < earliest_available_block {
64+
anyhow::bail!(
65+
"The data for block #{} is garbage collected on this node, use an archival node to fetch historical data",
66+
block_height
67+
)
68+
}
69+
Ok(())
70+
}

database/src/postgres/mod.rs

Lines changed: 20 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,27 @@ impl PageState {
2828
}
2929
}
3030

31+
/// This struct is used to manage the connection to a specific shard database.
32+
/// It contains the shard_id, data_range_id, and a reference to the database pool.
33+
/// `shard_id` is used to identify the shard database.
34+
/// `data_range_id` is used to identify the range of data in the shard database.
35+
/// `pool` is a reference to the database pool that is used to connect to the shard database.
36+
///
37+
/// `data_range_id` is calculated based on the block height.
38+
/// Since we split the database into ranges of 500,000 blocks,
39+
/// we can use the block height to determine the range.
40+
/// For database, we store ranges in different tables and use `data_range_id` as the suffix.
41+
/// `state_changes_data_{data_range_id}`
42+
///
43+
/// Example:
44+
/// block_height 73_908_345, the `data_range_id` will be 735 -> `state_changes_data_735`
45+
/// block_height 130_501_000, the `data_range_id` will be 1305 -> `state_changes_data_1305`
46+
///
47+
/// How to get `data_range_id` from block_height
48+
/// see more details in the `get_data_range_id` function below.
3149
pub struct ShardIdPool<'a> {
3250
shard_id: near_primitives::types::ShardId,
33-
table_number: u64,
51+
data_range_id: u64,
3452
pool: &'a sqlx::Pool<sqlx::Postgres>,
3553
}
3654

@@ -39,7 +57,6 @@ pub struct PostgresDBManager {
3957
shards_pool:
4058
std::collections::HashMap<near_primitives::types::ShardId, sqlx::Pool<sqlx::Postgres>>,
4159
meta_db_pool: sqlx::Pool<sqlx::Postgres>,
42-
earliest_available_block: Option<near_primitives::types::BlockHeight>,
4360
}
4461

4562
impl PostgresDBManager {
@@ -81,61 +98,14 @@ impl PostgresDBManager {
8198
let shard_id = self.shard_layout.account_id_to_shard_id(account_id);
8299
Ok(ShardIdPool {
83100
shard_id,
84-
table_number: self.get_table_number(block_height).await?,
101+
data_range_id: configuration::utils::get_data_range_id(block_height).await?,
85102
pool: self.shards_pool.get(&shard_id).ok_or(anyhow::anyhow!(
86103
"Database connection for Shard_{} not found",
87104
shard_id
88105
))?,
89106
})
90107
}
91108

92-
/// # Explanation of the logic:
93-
///
94-
/// 1. `block_height / 500000`
95-
///
96-
/// * This integer division truncates any remainder, effectively grouping numbers into bins of 500,000.
97-
///
98-
/// * Example: 73908345 / 500000 = 147 (as integer division discards the remainder).
99-
///
100-
/// 2. `* 5`
101-
///
102-
/// * Since each bin represents a multiple of 500,000, multiplying by 5 scales the result to match the pattern you provided.
103-
///
104-
/// # Example Calculations:
105-
/// Example 1: 73908345
106-
///
107-
/// 1. 73908345 / 500000 = 147
108-
///
109-
/// 2. 147 * 5 = 735
110-
///
111-
/// Output: 735
112-
///
113-
/// Example 2: 130501000
114-
///
115-
/// 1. 130501000 / 500000 = 261
116-
///
117-
/// 2. 261 * 5 = 1305
118-
///
119-
/// Output: 1305
120-
async fn get_table_number(
121-
&self,
122-
block_height: &near_primitives::types::BlockHeight,
123-
) -> anyhow::Result<u64> {
124-
if let Some(earliest_available_block) = self.earliest_available_block {
125-
if *block_height < earliest_available_block {
126-
anyhow::bail!(
127-
"Block {} has been garbage collected. The earliest available block is {}",
128-
block_height,
129-
earliest_available_block
130-
)
131-
} else {
132-
Ok((block_height / 500000) * 5)
133-
}
134-
} else {
135-
Ok((block_height / 500000) * 5)
136-
}
137-
}
138-
139109
async fn run_migrations(
140110
migrator: &sqlx::migrate::Migrator,
141111
pool: &sqlx::Pool<sqlx::Postgres>,
@@ -172,10 +142,6 @@ impl crate::BaseDbManager for PostgresDBManager {
172142
shard_layout,
173143
shards_pool,
174144
meta_db_pool,
175-
// TODO: This should be set from the config and not hardcoded
176-
// Should be updated when garbage collection is run
177-
// or should be None for archive node_mode
178-
earliest_available_block: None,
179145
}))
180146
}
181147
}

0 commit comments

Comments
 (0)