Skip to content

Commit 366c3ee

Browse files
authored
bugfix: handle new rate-limits for querying pools (#433)
Closes: #431 * Added fast-near for testnet * Rate limited querying pools to 140 / 30s Ideally, if Fastnear is stable enough, the user shouldn't be able to hit this limit as we will query information within the pools the user has staked before. But in case the fastener fails, we would need to query all active pools, which number more than 150. | Network | FastNear | Non fast near | | :---: | :---: | :---: | | Testnet | < 140 (mostly 0-5) | 563 pools | Mainnet | < 140 ( mostly 0-5 ) | State of contract poolv1.near is too large to be viewed | @race-of-sloths
1 parent 5927f4b commit 366c3ee

File tree

3 files changed

+97
-29
lines changed

3 files changed

+97
-29
lines changed

src/commands/account/view_account_summary/mod.rs

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ fn get_account_inquiry(
108108
crate::common::fetch_historically_delegated_staking_pools(fastnear_url, account_id)
109109
.ok()
110110
});
111-
let validators = if let Some(validators) = historically_delegated_validators {
112-
Ok(validators)
111+
let pools_to_query = if let Some(user_staked_pools) = historically_delegated_validators {
112+
Ok(user_staked_pools)
113113
} else if let Some(staking_pools_factory_account_id) =
114114
&network_config.staking_pools_factory_account_id
115115
{
@@ -124,32 +124,69 @@ fn get_account_inquiry(
124124
let runtime = tokio::runtime::Builder::new_multi_thread()
125125
.enable_all()
126126
.build()?;
127-
let concurrency = 10;
127+
// Staring from Feb 2025, the rate limit is 150 requests per 30 seconds for mainnet.
128+
// We will limit the number of requests per batch to 140 to be conservative.
129+
let batch_size = 140;
130+
let batch_cooldown = tokio::time::Duration::from_secs(30);
131+
let concurrency = 10; // Process 10 requests concurrently within each batch
132+
128133
let delegated_stake: color_eyre::Result<
129134
std::collections::BTreeMap<near_primitives::types::AccountId, near_token::NearToken>,
130-
> = match validators {
131-
Ok(validators) => Ok(runtime.block_on(
132-
futures::stream::iter(validators)
133-
.map(|validator_account_id| async {
134-
let balance = get_delegated_staked_balance(
135-
&json_rpc_client,
136-
block_reference,
137-
&validator_account_id,
138-
account_id,
139-
)
140-
.await?;
141-
Ok::<_, color_eyre::eyre::Report>((validator_account_id, balance))
142-
})
143-
.buffer_unordered(concurrency)
144-
.filter(|balance_result| {
145-
futures::future::ready(if let Ok((_, balance)) = balance_result {
146-
!balance.is_zero()
147-
} else {
148-
true
149-
})
150-
})
151-
.try_collect(),
152-
)?),
135+
> = match pools_to_query {
136+
Ok(validators) => {
137+
let mut all_results = Ok(std::collections::BTreeMap::new());
138+
let validators: Vec<_> = validators.into_iter().collect();
139+
140+
for (batch_index, validator_batch) in validators
141+
.chunks(batch_size)
142+
.map(|x| x.to_vec())
143+
.enumerate()
144+
{
145+
if batch_index > 0 {
146+
// Wait 30 seconds before starting next batch
147+
tracing::info!(
148+
"Waiting for 30 seconds before fetching next batch of stake information"
149+
);
150+
runtime.block_on(async { tokio::time::sleep(batch_cooldown).await });
151+
}
152+
153+
let batch_results = runtime.block_on(
154+
futures::stream::iter(validator_batch)
155+
.map(|validator_account_id| async {
156+
let balance = get_delegated_staked_balance(
157+
&json_rpc_client,
158+
block_reference,
159+
&validator_account_id,
160+
account_id,
161+
)
162+
.await?;
163+
Ok::<_, color_eyre::eyre::Report>((validator_account_id, balance))
164+
})
165+
.buffer_unordered(concurrency)
166+
.filter(|balance_result| {
167+
futures::future::ready(if let Ok((_, balance)) = balance_result {
168+
!balance.is_zero()
169+
} else {
170+
true
171+
})
172+
})
173+
.try_collect::<std::collections::BTreeMap<_, _>>(),
174+
);
175+
176+
match batch_results {
177+
Ok(batch_results) => {
178+
let _ = all_results.as_mut().map(|all_results| {
179+
all_results.extend(batch_results);
180+
});
181+
}
182+
Err(err) => {
183+
all_results = Err(err);
184+
break;
185+
}
186+
};
187+
}
188+
all_results
189+
}
153190
Err(err) => Err(err),
154191
};
155192

src/config/migrations.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::config::Config as ConfigV2;
1+
use crate::config::Config as ConfigV3;
22
use crate::config::NetworkConfig as NetworkConfigV2;
33

44
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
@@ -7,6 +7,12 @@ pub struct ConfigV1 {
77
pub network_connection: linked_hash_map::LinkedHashMap<String, NetworkConfigV1>,
88
}
99

10+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
11+
pub struct ConfigV2 {
12+
pub credentials_home_dir: std::path::PathBuf,
13+
pub network_connection: linked_hash_map::LinkedHashMap<String, NetworkConfigV2>,
14+
}
15+
1016
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1117
pub struct NetworkConfigV1 {
1218
pub network_name: String,
@@ -35,6 +41,25 @@ impl From<ConfigV1> for ConfigV2 {
3541
}
3642
}
3743

44+
impl From<ConfigV2> for ConfigV3 {
45+
fn from(config: ConfigV2) -> Self {
46+
ConfigV3 {
47+
credentials_home_dir: config.credentials_home_dir,
48+
network_connection: config
49+
.network_connection
50+
.into_iter()
51+
.map(|(network_name, mut network_config)| {
52+
if network_name == "testnet" && network_config.faucet_url.is_none() {
53+
network_config.fastnear_url =
54+
Some("https://test.api.fastnear.com/".parse().unwrap());
55+
}
56+
(network_name, network_config)
57+
})
58+
.collect(),
59+
}
60+
}
61+
}
62+
3863
impl From<NetworkConfigV1> for NetworkConfigV2 {
3964
fn from(network_config: NetworkConfigV1) -> Self {
4065
match network_config.network_name.as_str() {
@@ -94,4 +119,7 @@ pub enum ConfigVersion {
94119
V1(ConfigV1),
95120
#[serde(rename = "2")]
96121
V2(ConfigV2),
122+
// Adds fastnear_url to the testnet config if it's not present
123+
#[serde(rename = "3")]
124+
V3(ConfigV3),
97125
}

src/config/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl Config {
7474
}
7575

7676
pub fn into_latest_version(self) -> migrations::ConfigVersion {
77-
migrations::ConfigVersion::V2(self)
77+
migrations::ConfigVersion::V3(self)
7878
}
7979

8080
pub fn get_config_toml() -> color_eyre::eyre::Result<Self> {
@@ -193,7 +193,10 @@ impl From<migrations::ConfigVersion> for Config {
193193
migrations::ConfigVersion::V2(config_v1.into())
194194
}
195195
migrations::ConfigVersion::V2(config_v2) => {
196-
break config_v2;
196+
migrations::ConfigVersion::V3(config_v2.into())
197+
}
198+
migrations::ConfigVersion::V3(config_v3) => {
199+
break config_v3;
197200
}
198201
};
199202
}

0 commit comments

Comments
 (0)