@@ -25,7 +25,9 @@ use std::{
2525 atomic:: { AtomicBool , Ordering } ,
2626 Arc ,
2727 } ,
28+ time:: Duration ,
2829} ;
30+ use tokio:: time:: sleep;
2931use uuid:: Uuid ;
3032pub mod api;
3133#[ rustfmt:: skip]
@@ -43,6 +45,8 @@ use crate::solana_program::{
4345} ;
4446
4547const MAINNET_GENESIS_HASH : & str = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d" ;
48+ const MAX_RETRIES : u32 = 5 ;
49+ const INITIAL_RETRY_DELAY_MS : u64 = 500 ;
4650
4751pub 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> {
725729pub 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
733737pub 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
759765pub 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
764772pub 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