@@ -16,6 +16,7 @@ use solana_loader_v3_interface::{get_program_data_address, state::UpgradeableLoa
1616use solana_program:: get_address_from_keypair_or_config;
1717use solana_rpc_client:: rpc_client:: RpcClient ;
1818use solana_sdk:: pubkey:: Pubkey ;
19+ use solana_sdk_ids:: { bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable} ;
1920use solana_transaction_status_client_types:: UiTransactionEncoding ;
2021use std:: {
2122 io:: Read ,
@@ -725,33 +726,83 @@ pub fn get_file_hash(filepath: &str) -> Result<String, std::io::Error> {
725726pub fn get_buffer_hash ( url : Option < String > , buffer_address : Pubkey ) -> anyhow:: Result < String > {
726727 let client = get_client ( url, None ) ;
727728 let offset = UpgradeableLoaderState :: size_of_buffer_metadata ( ) ;
728- let account_data = client. get_account_data ( & buffer_address) ?[ offset..] . to_vec ( ) ;
729+ let data = client. get_account_data ( & buffer_address) ?;
730+ let account_data = data
731+ . get ( offset..)
732+ . ok_or_else ( || {
733+ anyhow:: anyhow!(
734+ "Buffer account {} appears invalid or incomplete. Expected at least {} bytes for metadata." ,
735+ buffer_address,
736+ offset
737+ )
738+ } ) ?
739+ . to_vec ( ) ;
740+
729741 let program_hash = get_binary_hash ( account_data) ;
730742 Ok ( program_hash)
731743}
732744
733745pub fn get_program_hash ( client : & RpcClient , program_id : Pubkey ) -> anyhow:: Result < String > {
734- // 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- }
738-
739- let program_buffer = get_program_data_address ( & program_id) ;
746+ let account = client
747+ . get_account ( & program_id)
748+ . map_err ( |e| anyhow ! ( "Program {} is not deployed: {}" , program_id, e) ) ?;
749+
750+ let owner = account. owner ;
751+
752+ match owner {
753+ // Check if the program is owned by the upgradeable loader (Loader-v3)
754+ // If so, the program data is in a separate program data account
755+ owner_id if owner_id == bpf_loader_upgradeable:: id ( ) => {
756+ let program_buffer = get_program_data_address ( & program_id) ;
757+
758+ // Get the program data account
759+ let data = client. get_account_data ( & program_buffer) . map_err ( |e| {
760+ anyhow ! (
761+ "Could not find program data for {}: {}. This could mean:\n \
762+ 1. The program is not deployed\n \
763+ 2. The program is not upgradeable\n \
764+ 3. The program was deployed with a different loader",
765+ program_id,
766+ e
767+ )
768+ } ) ?;
740769
741- // Then check if the program data account exists
742- match client. get_account_data ( & program_buffer) {
743- Ok ( data) => {
744770 let offset = UpgradeableLoaderState :: size_of_programdata_metadata ( ) ;
745- let account_data = data[ offset..] . to_vec ( ) ;
746- let program_hash = get_binary_hash ( account_data) ;
747- Ok ( program_hash)
771+
772+ let account_data = data
773+ . get ( offset..)
774+ . ok_or_else ( || {
775+ anyhow ! (
776+ "Program data account appears corrupted or incomplete. Expected at least {} bytes for metadata." ,
777+ offset
778+ )
779+ } ) ?
780+ . to_vec ( ) ;
781+
782+ Ok ( get_binary_hash ( account_data) )
748783 }
749- Err ( _) => Err ( anyhow ! (
750- "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",
754- program_id
784+
785+ // Check if the program is owned by the legacy BPF loaders (v1/v2)
786+ // If so, the program data is stored in the program account's data
787+ owner_id if owner_id == bpf_loader_deprecated:: id ( ) || owner_id == bpf_loader:: id ( ) => {
788+ let program_data = account. data ;
789+
790+ if program_data. is_empty ( ) {
791+ return Err ( anyhow ! (
792+ "Program {} has no data (legacy loader account empty)" ,
793+ program_id
794+ ) ) ;
795+ }
796+
797+ Ok ( get_binary_hash ( program_data) )
798+ }
799+
800+ // Unsupported loader
801+ _ => Err ( anyhow ! (
802+ "Unknown or unsupported program loader. \
803+ Program {} is owned by {}. Supported loaders: BPF Loader v1, v2, or Upgradeable (loader-v3).",
804+ program_id,
805+ owner
755806 ) ) ,
756807 }
757808}
@@ -772,7 +823,9 @@ pub fn get_docker_resource_limits() -> Option<(String, String)> {
772823 } else {
773824 // Print message to user that they can set these environment variables to limit docker resources
774825 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." ) ;
826+ println ! (
827+ "You can set the SVB_DOCKER_MEMORY_LIMIT and SVB_DOCKER_CPU_LIMIT environment variables to limit Docker resources."
828+ ) ;
776829 println ! ( "For example: SVB_DOCKER_MEMORY_LIMIT=2g SVB_DOCKER_CPU_LIMIT=2." ) ;
777830 }
778831 memory. zip ( cpus)
@@ -1086,10 +1139,7 @@ pub fn verify_from_image(
10861139
10871140 let executable_hash: String = get_file_hash ( program_filepath. as_str ( ) ) ?;
10881141 let client = get_client ( network, config_path) ;
1089- let program_buffer = get_program_data_address ( & program_id) ;
1090- let offset = UpgradeableLoaderState :: size_of_programdata_metadata ( ) ;
1091- let account_data = & client. get_account_data ( & program_buffer) ?[ offset..] ;
1092- let program_hash = get_binary_hash ( account_data. to_vec ( ) ) ;
1142+ let program_hash = get_program_hash ( & client, program_id) ?;
10931143 println ! ( "Executable hash: {}" , executable_hash) ;
10941144 println ! ( "Program hash: {}" , program_hash) ;
10951145
@@ -1392,7 +1442,9 @@ pub async fn verify_from_repo(
13921442 check_signal ( container_id_opt, temp_dir_opt) ;
13931443 let genesis_hash = get_genesis_hash ( connection) ?;
13941444 if genesis_hash != MAINNET_GENESIS_HASH {
1395- return Err ( anyhow ! ( "Remote verification only works with mainnet. Please omit the --remote flag to verify locally." ) ) ;
1445+ return Err ( anyhow ! (
1446+ "Remote verification only works with mainnet. Please omit the --remote flag to verify locally."
1447+ ) ) ;
13961448 }
13971449
13981450 let uploader = get_address_from_keypair_or_config (
0 commit comments