@@ -168,8 +168,9 @@ pub enum ProgramCliCommand {
168168 use_lamports_unit : bool ,
169169 bypass_warning : bool ,
170170 } ,
171- ExtendProgram {
171+ ExtendProgramChecked {
172172 program_pubkey : Pubkey ,
173+ authority_signer_index : SignerIndex ,
173174 additional_bytes : u32 ,
174175 } ,
175176 MigrateProgram {
@@ -1008,17 +1009,22 @@ pub fn parse_program_subcommand(
10081009 let program_pubkey = pubkey_of ( matches, "program_id" ) . unwrap ( ) ;
10091010 let additional_bytes = value_of ( matches, "additional_bytes" ) . unwrap ( ) ;
10101011
1012+ let ( authority_signer, authority_pubkey) =
1013+ signer_of ( matches, "authority" , wallet_manager) ?;
1014+
10111015 let signer_info = default_signer. generate_unique_signers (
1012- vec ! [ Some (
1013- default_signer. signer_from_path( matches, wallet_manager) ?,
1014- ) ] ,
1016+ vec ! [
1017+ Some ( default_signer. signer_from_path( matches, wallet_manager) ?) ,
1018+ authority_signer,
1019+ ] ,
10151020 matches,
10161021 wallet_manager,
10171022 ) ?;
10181023
10191024 CliCommandInfo {
1020- command : CliCommand :: Program ( ProgramCliCommand :: ExtendProgram {
1025+ command : CliCommand :: Program ( ProgramCliCommand :: ExtendProgramChecked {
10211026 program_pubkey,
1027+ authority_signer_index : signer_info. index_of ( authority_pubkey) . unwrap ( ) ,
10221028 additional_bytes,
10231029 } ) ,
10241030 signers : signer_info. signers ,
@@ -1230,10 +1236,17 @@ pub fn process_program_subcommand(
12301236 * use_lamports_unit,
12311237 * bypass_warning,
12321238 ) ,
1233- ProgramCliCommand :: ExtendProgram {
1239+ ProgramCliCommand :: ExtendProgramChecked {
12341240 program_pubkey,
1241+ authority_signer_index,
12351242 additional_bytes,
1236- } => process_extend_program ( & rpc_client, config, * program_pubkey, * additional_bytes) ,
1243+ } => process_extend_program (
1244+ & rpc_client,
1245+ config,
1246+ * program_pubkey,
1247+ * authority_signer_index,
1248+ * additional_bytes,
1249+ ) ,
12371250 ProgramCliCommand :: MigrateProgram {
12381251 program_pubkey,
12391252 authority_signer_index,
@@ -2365,9 +2378,11 @@ fn process_extend_program(
23652378 rpc_client : & RpcClient ,
23662379 config : & CliConfig ,
23672380 program_pubkey : Pubkey ,
2381+ authority_signer_index : SignerIndex ,
23682382 additional_bytes : u32 ,
23692383) -> ProcessResult {
23702384 let payer_pubkey = config. signers [ 0 ] . pubkey ( ) ;
2385+ let authority_signer = config. signers [ authority_signer_index] ;
23712386
23722387 if additional_bytes == 0 {
23732388 return Err ( "Additional bytes must be greater than zero" . into ( ) ) ;
@@ -2410,23 +2425,39 @@ fn process_extend_program(
24102425 _ => Err ( format ! ( "Program {program_pubkey} is closed" ) ) ,
24112426 } ?;
24122427
2413- match upgrade_authority_address {
2414- None => Err ( format ! ( "Program {program_pubkey} is not upgradeable" ) ) ,
2415- _ => Ok ( ( ) ) ,
2416- } ?;
2428+ let upgrade_authority_address = upgrade_authority_address
2429+ . ok_or_else ( || format ! ( "Program {program_pubkey} is not upgradeable" ) ) ?;
24172430
2418- let blockhash = rpc_client. get_latest_blockhash ( ) ?;
2431+ if authority_signer. pubkey ( ) != upgrade_authority_address {
2432+ return Err ( format ! (
2433+ "Upgrade authority {} does not match {}" ,
2434+ upgrade_authority_address,
2435+ authority_signer. pubkey( ) ,
2436+ )
2437+ . into ( ) ) ;
2438+ }
24192439
2420- let mut tx = Transaction :: new_unsigned ( Message :: new (
2421- & [ loader_v3_instruction:: extend_program (
2422- & program_pubkey,
2423- Some ( & payer_pubkey) ,
2424- additional_bytes,
2425- ) ] ,
2426- Some ( & payer_pubkey) ,
2427- ) ) ;
2440+ let blockhash = rpc_client. get_latest_blockhash ( ) ?;
2441+ let feature_set = fetch_feature_set ( rpc_client) ?;
2442+
2443+ let instruction =
2444+ if feature_set. is_active ( & agave_feature_set:: enable_extend_program_checked:: id ( ) ) {
2445+ loader_v3_instruction:: extend_program_checked (
2446+ & program_pubkey,
2447+ & upgrade_authority_address,
2448+ Some ( & payer_pubkey) ,
2449+ additional_bytes,
2450+ )
2451+ } else {
2452+ loader_v3_instruction:: extend_program (
2453+ & program_pubkey,
2454+ Some ( & payer_pubkey) ,
2455+ additional_bytes,
2456+ )
2457+ } ;
2458+ let mut tx = Transaction :: new_unsigned ( Message :: new ( & [ instruction] , Some ( & payer_pubkey) ) ) ;
24282459
2429- tx. try_sign ( & [ config. signers [ 0 ] ] , blockhash) ?;
2460+ tx. try_sign ( & [ config. signers [ 0 ] , authority_signer ] , blockhash) ?;
24302461 let result = rpc_client. send_and_confirm_transaction_with_spinner_and_config (
24312462 & tx,
24322463 config. commitment ,
@@ -2971,6 +3002,17 @@ fn extend_program_data_if_needed(
29713002 return Ok ( ( ) ) ;
29723003 } ;
29733004
3005+ let upgrade_authority_address = match program_data_account. state ( ) {
3006+ Ok ( UpgradeableLoaderState :: ProgramData {
3007+ slot : _,
3008+ upgrade_authority_address,
3009+ } ) => Ok ( upgrade_authority_address) ,
3010+ _ => Err ( format ! ( "Program {program_id} is closed" ) ) ,
3011+ } ?;
3012+
3013+ let upgrade_authority_address = upgrade_authority_address
3014+ . ok_or_else ( || format ! ( "Program {program_id} is not upgradeable" ) ) ?;
3015+
29743016 let required_len = UpgradeableLoaderState :: size_of_programdata ( program_len) ;
29753017 let max_permitted_data_length = usize:: try_from ( MAX_PERMITTED_DATA_LENGTH ) . unwrap ( ) ;
29763018 if required_len > max_permitted_data_length {
@@ -2992,11 +3034,20 @@ fn extend_program_data_if_needed(
29923034
29933035 let additional_bytes =
29943036 u32:: try_from ( additional_bytes) . expect ( "`u32` is big enough to hold an account size" ) ;
2995- initial_instructions. push ( loader_v3_instruction:: extend_program (
2996- program_id,
2997- Some ( fee_payer) ,
2998- additional_bytes,
2999- ) ) ;
3037+
3038+ let feature_set = fetch_feature_set ( rpc_client) ?;
3039+ let instruction =
3040+ if feature_set. is_active ( & agave_feature_set:: enable_extend_program_checked:: id ( ) ) {
3041+ loader_v3_instruction:: extend_program_checked (
3042+ program_id,
3043+ & upgrade_authority_address,
3044+ Some ( fee_payer) ,
3045+ additional_bytes,
3046+ )
3047+ } else {
3048+ loader_v3_instruction:: extend_program ( program_id, Some ( fee_payer) , additional_bytes)
3049+ } ;
3050+ initial_instructions. push ( instruction) ;
30003051
30013052 Ok ( ( ) )
30023053}
@@ -3091,7 +3142,12 @@ fn send_deploy_messages(
30913142 // account to sign the transaction. One (transfer) only requires the fee-payer signature.
30923143 // This check is to ensure signing does not fail on a KeypairPubkeyMismatch error from an
30933144 // extraneous signature.
3094- if message. header . num_required_signatures == 2 {
3145+ if message. header . num_required_signatures == 3 {
3146+ initial_transaction. try_sign (
3147+ & [ fee_payer_signer, initial_signer, write_signer. unwrap ( ) ] ,
3148+ blockhash,
3149+ ) ?;
3150+ } else if message. header . num_required_signatures == 2 {
30953151 initial_transaction. try_sign ( & [ fee_payer_signer, initial_signer] , blockhash) ?;
30963152 } else {
30973153 initial_transaction. try_sign ( & [ fee_payer_signer] , blockhash) ?;
@@ -4401,8 +4457,9 @@ mod tests {
44014457 assert_eq ! (
44024458 parse_command( & test_command, & default_signer, & mut None ) . unwrap( ) ,
44034459 CliCommandInfo {
4404- command: CliCommand :: Program ( ProgramCliCommand :: ExtendProgram {
4460+ command: CliCommand :: Program ( ProgramCliCommand :: ExtendProgramChecked {
44054461 program_pubkey,
4462+ authority_signer_index: 0 ,
44064463 additional_bytes
44074464 } ) ,
44084465 signers: vec![ Box :: new( read_keypair_file( & keypair_file) . unwrap( ) ) ] ,
0 commit comments