Skip to content

Commit 1ad1db1

Browse files
authored
feat: added ability to specify backup rpc for connecting to the network (#28)
* feat: added ability to specify backup rpc for connecting to the network * fmt
1 parent 3982a3f commit 1ad1db1

File tree

7 files changed

+185
-173
lines changed

7 files changed

+185
-173
lines changed

examples/specify_backup_rpc.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use near_api::{prelude::*, types::reference::Reference};
2+
3+
#[tokio::main]
4+
async fn main() {
5+
let mut network = NetworkConfig::mainnet();
6+
network.rpc_endpoints.push(
7+
RPCEndpoint::new("https://rpc.mainnet.pagoda.co/".parse().unwrap())
8+
.with_api_key("potential api key".parse().unwrap())
9+
.with_retries(5),
10+
);
11+
// Query latest block
12+
let _block = Chain::block()
13+
.at(Reference::Optimistic)
14+
.fetch_from_mainnet()
15+
.await
16+
.unwrap();
17+
}

src/common/query.rs

Lines changed: 28 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ use serde::de::DeserializeOwned;
1818
use tracing::{debug, error, info, instrument, trace, warn};
1919

2020
use crate::{
21-
common::utils::{retry, RetryResponse},
22-
config::NetworkConfig,
21+
config::{retry, NetworkConfig, RetryResponse},
2322
errors::QueryError,
2423
types::Data,
2524
};
@@ -155,9 +154,6 @@ where
155154
reference: Reference,
156155
requests: Vec<Arc<dyn QueryCreator<Method, RpcReference = Reference> + Send + Sync>>,
157156
handler: ResponseHandler,
158-
retries: u8,
159-
sleep_duration: std::time::Duration,
160-
exponential_backoff: bool,
161157
}
162158

163159
impl<Handler, Method, Reference> MultiRpcBuilder<Handler, Method, Reference>
@@ -173,10 +169,6 @@ where
173169
reference,
174170
requests: vec![],
175171
handler,
176-
retries: 5,
177-
// 50ms, 100ms, 200ms, 400ms, 800ms
178-
sleep_duration: std::time::Duration::from_millis(50),
179-
exponential_backoff: true,
180172
}
181173
}
182174

@@ -205,8 +197,6 @@ where
205197
self,
206198
network: &NetworkConfig,
207199
) -> ResultWithMethod<Handler::Response, Method> {
208-
let json_rpc_client = network.json_rpc_client();
209-
210200
debug!(target: QUERY_EXECUTOR_TARGET, "Preparing queries");
211201
let requests: Vec<_> = self
212202
.requests
@@ -219,32 +209,27 @@ where
219209
.collect::<Result<_, _>>()?;
220210

221211
info!(target: QUERY_EXECUTOR_TARGET, "Sending {} queries", requests.len());
222-
let requests = requests.into_iter().map(|(query, request)| {
223-
let json_rpc_client = json_rpc_client.clone();
224-
async move {
225-
retry(
226-
|| async {
227-
let result = match json_rpc_client.call(&query).await {
228-
Ok(result) => RetryResponse::Ok(result),
229-
Err(err) if request.is_critical_error(&err) => {
230-
RetryResponse::Critical(err)
231-
}
232-
Err(err) => RetryResponse::Retry(err),
233-
};
234-
tracing::debug!(
235-
target: QUERY_EXECUTOR_TARGET,
236-
"Querying RPC with {:?} resulted in {:?}",
237-
query,
238-
result
239-
);
212+
let requests = requests.into_iter().map(|(query, request)| async move {
213+
retry(network.clone(), |json_rpc_client| {
214+
let query = &query;
215+
let request = &request;
216+
217+
async move {
218+
let result = match json_rpc_client.call(&query).await {
219+
Ok(result) => RetryResponse::Ok(result),
220+
Err(err) if request.is_critical_error(&err) => RetryResponse::Critical(err),
221+
Err(err) => RetryResponse::Retry(err),
222+
};
223+
tracing::debug!(
224+
target: QUERY_EXECUTOR_TARGET,
225+
"Querying RPC with {:?} resulted in {:?}",
226+
query,
240227
result
241-
},
242-
self.retries,
243-
self.sleep_duration,
244-
self.exponential_backoff,
245-
)
246-
.await
247-
}
228+
);
229+
result
230+
}
231+
})
232+
.await
248233
});
249234

250235
let requests: Vec<_> = join_all(requests)
@@ -275,9 +260,6 @@ pub struct RpcBuilder<Handler, Method, Reference> {
275260
reference: Reference,
276261
request: Arc<dyn QueryCreator<Method, RpcReference = Reference> + Send + Sync>,
277262
handler: Handler,
278-
retries: u8,
279-
sleep_duration: std::time::Duration,
280-
exponential_backoff: bool,
281263
}
282264

283265
impl<Handler, Method, Reference> RpcBuilder<Handler, Method, Reference>
@@ -297,10 +279,6 @@ where
297279
reference,
298280
request: Arc::new(request),
299281
handler,
300-
retries: 5,
301-
// 50ms, 100ms, 200ms, 400ms, 800ms
302-
sleep_duration: std::time::Duration::from_millis(50),
303-
exponential_backoff: true,
304282
}
305283
}
306284

@@ -311,37 +289,21 @@ where
311289
}
312290
}
313291

314-
pub const fn with_retries(mut self, retries: u8) -> Self {
315-
self.retries = retries;
316-
self
317-
}
318-
319-
pub const fn with_sleep_duration(mut self, sleep_duration: std::time::Duration) -> Self {
320-
self.sleep_duration = sleep_duration;
321-
self
322-
}
323-
324-
pub const fn with_exponential_backoff(mut self) -> Self {
325-
self.exponential_backoff = true;
326-
self
327-
}
328-
329292
#[instrument(skip(self, network))]
330293
pub async fn fetch_from(
331294
self,
332295
network: &NetworkConfig,
333296
) -> ResultWithMethod<Handler::Response, Method> {
334297
debug!(target: QUERY_EXECUTOR_TARGET, "Preparing query");
335-
let json_rpc_client = network.json_rpc_client();
336298
let query = self.request.create_query(network, self.reference)?;
337299

338-
let query_response = retry(
339-
|| async {
300+
let query_response = retry(network.clone(), |json_rpc_client| {
301+
let query = &query;
302+
let request = &self.request;
303+
async move {
340304
let result = match json_rpc_client.call(&query).await {
341305
Ok(result) => RetryResponse::Ok(result),
342-
Err(err) if self.request.is_critical_error(&err) => {
343-
RetryResponse::Critical(err)
344-
}
306+
Err(err) if request.is_critical_error(&err) => RetryResponse::Critical(err),
345307
Err(err) => RetryResponse::Retry(err),
346308
};
347309
tracing::debug!(
@@ -351,11 +313,8 @@ where
351313
result
352314
);
353315
result
354-
},
355-
3,
356-
std::time::Duration::from_secs(1),
357-
false,
358-
)
316+
}
317+
})
359318
.await?;
360319

361320
debug!(target: QUERY_EXECUTOR_TARGET, "Processing query response");

src/common/send.rs

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use reqwest::Response;
1111
use tracing::{debug, info};
1212

1313
use crate::{
14-
common::utils::{is_critical_transaction_error, RetryResponse},
15-
config::NetworkConfig,
14+
common::utils::is_critical_transaction_error,
15+
config::{retry, NetworkConfig, RetryResponse},
1616
errors::{
1717
ExecuteMetaTransactionsError, ExecuteTransactionError, MetaSignError, SignerError,
1818
ValidationError,
@@ -22,8 +22,7 @@ use crate::{
2222
};
2323

2424
use super::{
25-
signed_delegate_action::SignedDelegateActionAsBase64, utils::retry,
26-
META_TRANSACTION_VALID_FOR_DEFAULT,
25+
signed_delegate_action::SignedDelegateActionAsBase64, META_TRANSACTION_VALID_FOR_DEFAULT,
2726
};
2827

2928
const TX_EXECUTOR_TARGET: &str = "near_api::tx::executor";
@@ -80,42 +79,20 @@ impl From<SignedTransaction> for PrepopulateTransaction {
8079
pub struct ExecuteSignedTransaction {
8180
pub tr: TransactionableOrSigned<SignedTransaction>,
8281
pub signer: Arc<Signer>,
83-
pub retries: u8,
84-
pub sleep_duration: std::time::Duration,
85-
pub exponential_backoff: bool,
8682
}
8783

8884
impl ExecuteSignedTransaction {
8985
pub fn new<T: Transactionable + 'static>(tr: T, signer: Arc<Signer>) -> Self {
9086
Self {
9187
tr: TransactionableOrSigned::Transactionable(Box::new(tr)),
9288
signer,
93-
retries: 5,
94-
// 50ms, 100ms, 200ms, 400ms, 800ms
95-
sleep_duration: std::time::Duration::from_millis(50),
96-
exponential_backoff: true,
9789
}
9890
}
9991

10092
pub fn meta(self) -> ExecuteMetaTransaction {
10193
ExecuteMetaTransaction::from_box(self.tr.transactionable(), self.signer)
10294
}
10395

104-
pub const fn with_retries(mut self, retries: u8) -> Self {
105-
self.retries = retries;
106-
self
107-
}
108-
109-
pub const fn with_sleep_duration(mut self, sleep_duration: std::time::Duration) -> Self {
110-
self.sleep_duration = sleep_duration;
111-
self
112-
}
113-
114-
pub const fn with_exponential_backoff(mut self) -> Self {
115-
self.exponential_backoff = true;
116-
self
117-
}
118-
11996
pub async fn presign_offline(
12097
mut self,
12198
public_key: PublicKey,
@@ -169,9 +146,6 @@ impl ExecuteSignedTransaction {
169146
mut self,
170147
network: &NetworkConfig,
171148
) -> Result<FinalExecutionOutcomeView, ExecuteTransactionError> {
172-
let sleep_duration = self.sleep_duration;
173-
let retries = self.retries;
174-
175149
let (signed, transactionable) = match &mut self.tr {
176150
TransactionableOrSigned::Transactionable(tr) => {
177151
debug!(target: TX_EXECUTOR_TARGET, "Preparing unsigned transaction");
@@ -212,7 +186,7 @@ impl ExecuteSignedTransaction {
212186
signed.transaction.nonce(),
213187
);
214188

215-
Self::send_impl(network, signed, retries, sleep_duration).await
189+
Self::send_impl(network, signed).await
216190
}
217191

218192
pub async fn send_to_mainnet(
@@ -232,15 +206,11 @@ impl ExecuteSignedTransaction {
232206
async fn send_impl(
233207
network: &NetworkConfig,
234208
signed_tr: SignedTransaction,
235-
retries: u8,
236-
sleep_duration: std::time::Duration,
237209
) -> Result<FinalExecutionOutcomeView, ExecuteTransactionError> {
238-
retry(
239-
|| {
240-
let signed_tr = signed_tr.clone();
241-
async move {
242-
let result = match network
243-
.json_rpc_client()
210+
retry(network.clone(), |json_rpc_client| {
211+
let signed_tr = signed_tr.clone();
212+
async move {
213+
let result = match json_rpc_client
244214
.call(
245215
near_jsonrpc_client::methods::broadcast_tx_commit::RpcBroadcastTxCommitRequest {
246216
signed_transaction: signed_tr.clone(),
@@ -263,9 +233,6 @@ impl ExecuteSignedTransaction {
263233
result
264234
}
265235
},
266-
retries,
267-
sleep_duration,
268-
false,
269236
)
270237
.await
271238
.map_err(ExecuteTransactionError::TransactionError)

src/common/utils.rs

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// https://github.com/near/near-token-rs/blob/3feafec624e7d1028ed00695f2acf87e1d823fa7/src/utils.rs#L1-L49
22

3-
use crate::errors::{DecimalNumberParsingError, RetryError};
3+
use crate::errors::DecimalNumberParsingError;
44

55
/// Parsing decimal numbers from `&str` type in `u128`.
66
/// Function also takes a value of metric prefix in u128 type.
@@ -49,55 +49,6 @@ pub fn parse_decimal_number(s: &str, pref_const: u128) -> Result<u128, DecimalNu
4949
Ok(result)
5050
}
5151

52-
#[derive(Debug)]
53-
pub enum RetryResponse<R, E> {
54-
Ok(R),
55-
Retry(E),
56-
Critical(E),
57-
}
58-
59-
impl<R, E> From<Result<R, E>> for RetryResponse<R, E> {
60-
fn from(value: Result<R, E>) -> Self {
61-
match value {
62-
Ok(value) => Self::Ok(value),
63-
Err(value) => Self::Retry(value),
64-
}
65-
}
66-
}
67-
68-
pub async fn retry<R, E, T, F>(
69-
mut task: F,
70-
retries: u8,
71-
initial_sleep: std::time::Duration,
72-
exponential_backoff: bool,
73-
) -> Result<R, RetryError<E>>
74-
where
75-
F: FnMut() -> T + Send,
76-
T: core::future::Future<Output = RetryResponse<R, E>> + Send,
77-
T::Output: Send,
78-
{
79-
let mut retries = (1..=retries).rev();
80-
let mut sleep_duration = initial_sleep;
81-
loop {
82-
let result = task().await;
83-
match result {
84-
RetryResponse::Ok(result) => return Ok(result),
85-
RetryResponse::Retry(_) if retries.next().is_some() => {
86-
tokio::time::sleep(sleep_duration).await;
87-
sleep_duration = if exponential_backoff {
88-
sleep_duration * 2
89-
} else {
90-
sleep_duration
91-
};
92-
}
93-
RetryResponse::Retry(err) => {
94-
return Err(RetryError::RetriesExhausted(err));
95-
}
96-
RetryResponse::Critical(err) => return Err(RetryError::Critical(err)),
97-
}
98-
}
99-
}
100-
10152
pub fn is_critical_blocks_error(
10253
err: &near_jsonrpc_client::errors::JsonRpcError<
10354
near_jsonrpc_primitives::types::blocks::RpcBlockError,

0 commit comments

Comments
 (0)