Skip to content

Commit 023be7e

Browse files
committed
feat: Add retries for RPC calls
1 parent d3811ef commit 023be7e

File tree

1 file changed

+54
-18
lines changed

1 file changed

+54
-18
lines changed

src/main.rs

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ use std::{
2525
atomic::{AtomicBool, Ordering},
2626
Arc,
2727
},
28+
time::Duration,
2829
};
30+
use tokio::time::sleep;
2931
use uuid::Uuid;
3032
pub mod api;
3133
#[rustfmt::skip]
@@ -43,6 +45,8 @@ use crate::solana_program::{
4345
};
4446

4547
const MAINNET_GENESIS_HASH: &str = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
48+
const MAX_RETRIES: u32 = 5;
49+
const INITIAL_RETRY_DELAY_MS: u64 = 500;
4650

4751
pub fn get_network(network_str: &str) -> &str {
4852
match network_str {
@@ -725,40 +729,44 @@ pub fn get_file_hash(filepath: &str) -> Result<String, std::io::Error> {
725729
pub fn get_buffer_hash(url: Option<String>, buffer_address: Pubkey) -> anyhow::Result<String> {
726730
let client = get_client(url, None);
727731
let offset = UpgradeableLoaderState::size_of_buffer_metadata();
728-
let account_data = client.get_account_data(&buffer_address)?[offset..].to_vec();
729-
let program_hash = get_binary_hash(account_data);
730-
Ok(program_hash)
732+
let account_data =
733+
retry_rpc_call(|| Ok(client.get_account_data(&buffer_address)?[offset..].to_vec()))?;
734+
Ok(get_binary_hash(account_data))
731735
}
732736

733737
pub fn get_program_hash(client: &RpcClient, program_id: Pubkey) -> anyhow::Result<String> {
734738
// First check if the program account exists
735-
if client.get_account(&program_id).is_err() {
736-
return Err(anyhow!("Program {} is not deployed", program_id));
737-
}
739+
retry_rpc_call(|| {
740+
if client.get_account(&program_id).is_err() {
741+
return Err(anyhow!("Program {} is not deployed", program_id));
742+
}
743+
Ok(())
744+
})?;
738745

739746
let program_buffer = get_program_data_address(&program_id);
740747

741748
// Then check if the program data account exists
742-
match client.get_account_data(&program_buffer) {
749+
let offset = UpgradeableLoaderState::size_of_programdata_metadata();
750+
retry_rpc_call(|| match client.get_account_data(&program_buffer) {
743751
Ok(data) => {
744-
let offset = UpgradeableLoaderState::size_of_programdata_metadata();
745752
let account_data = data[offset..].to_vec();
746-
let program_hash = get_binary_hash(account_data);
747-
Ok(program_hash)
753+
Ok(get_binary_hash(account_data))
748754
}
749755
Err(_) => Err(anyhow!(
750756
"Could not find program data for {}. This could mean:\n\
751-
1. The program is not deployed\n\
752-
2. The program is not upgradeable\n\
753-
3. The program was deployed with a different loader",
757+
1. The program is not deployed\n\
758+
2. The program is not upgradeable\n\
759+
3. The program was deployed with a different loader",
754760
program_id
755761
)),
756-
}
762+
})
757763
}
758764

759765
pub fn get_genesis_hash(client: &RpcClient) -> anyhow::Result<String> {
760-
let genesis_hash = client.get_genesis_hash()?;
761-
Ok(genesis_hash.to_string())
766+
retry_rpc_call(|| {
767+
let genesis_hash = client.get_genesis_hash()?;
768+
Ok(genesis_hash.to_string())
769+
})
762770
}
763771

764772
pub fn get_docker_resource_limits() -> Option<(String, String)> {
@@ -772,7 +780,9 @@ pub fn get_docker_resource_limits() -> Option<(String, String)> {
772780
} else {
773781
// Print message to user that they can set these environment variables to limit docker resources
774782
println!("No Docker resource limits are set.");
775-
println!("You can set the SVB_DOCKER_MEMORY_LIMIT and SVB_DOCKER_CPU_LIMIT environment variables to limit Docker resources.");
783+
println!(
784+
"You can set the SVB_DOCKER_MEMORY_LIMIT and SVB_DOCKER_CPU_LIMIT environment variables to limit Docker resources."
785+
);
776786
println!("For example: SVB_DOCKER_MEMORY_LIMIT=2g SVB_DOCKER_CPU_LIMIT=2.");
777787
}
778788
memory.zip(cpus)
@@ -1392,7 +1402,9 @@ pub async fn verify_from_repo(
13921402
check_signal(container_id_opt, temp_dir_opt);
13931403
let genesis_hash = get_genesis_hash(connection)?;
13941404
if genesis_hash != MAINNET_GENESIS_HASH {
1395-
return Err(anyhow!("Remote verification only works with mainnet. Please omit the --remote flag to verify locally."));
1405+
return Err(anyhow!(
1406+
"Remote verification only works with mainnet. Please omit the --remote flag to verify locally."
1407+
));
13961408
}
13971409

13981410
let uploader = get_address_from_keypair_or_config(
@@ -1702,3 +1714,27 @@ fn find_relative_manifest_path_and_build_path(
17021714
))
17031715
})
17041716
}
1717+
1718+
fn retry_rpc_call<F, T>(mut rpc_call: F) -> anyhow::Result<T>
1719+
where
1720+
F: FnMut() -> anyhow::Result<T>,
1721+
{
1722+
let mut attempts = 0;
1723+
let mut delay = INITIAL_RETRY_DELAY_MS;
1724+
1725+
loop {
1726+
match rpc_call() {
1727+
Ok(result) => return Ok(result),
1728+
Err(err) if attempts < MAX_RETRIES => {
1729+
attempts += 1;
1730+
println!(
1731+
"RPC call failed (attempt {}/{}) - retrying in {} ms... Error: {}",
1732+
attempts, MAX_RETRIES, delay, err
1733+
);
1734+
_ = sleep(Duration::from_millis(delay));
1735+
delay *= 2;
1736+
}
1737+
Err(err) => return Err(err),
1738+
}
1739+
}
1740+
}

0 commit comments

Comments
 (0)