1use hpsvm::{HPSVM, types::FailedTransactionMetadata};
4use solana_address::Address;
5use solana_keypair::Keypair;
6use solana_loader_v3_interface::{
7 instruction as bpf_loader_upgradeable, state::UpgradeableLoaderState,
8};
9use solana_signer::Signer;
10use solana_transaction::Transaction;
11
12const CHUNK_SIZE: usize = 512;
13
14pub fn set_upgrade_authority(
16 svm: &mut HPSVM,
17 from_keypair: &Keypair,
18 program_address: &Address,
19 current_authority_keypair: &Keypair,
20 new_authority_address: Option<&Address>,
21) -> Result<(), FailedTransactionMetadata> {
22 let mut signers: Vec<&dyn Signer> = vec![from_keypair];
23 if from_keypair.pubkey() != current_authority_keypair.pubkey() {
24 signers.push(current_authority_keypair);
25 }
26
27 let tx = Transaction::new_signed_with_payer(
28 &[bpf_loader_upgradeable::set_upgrade_authority(
29 program_address,
30 ¤t_authority_keypair.pubkey(),
31 new_authority_address,
32 )],
33 Some(&from_keypair.pubkey()),
34 &signers,
35 svm.latest_blockhash(),
36 );
37
38 svm.send_transaction(tx)?;
39
40 Ok(())
41}
42
43fn load_upgradeable_buffer(
44 svm: &mut HPSVM,
45 payer_kp: &Keypair,
46 program_bytes: &[u8],
47) -> Result<Address, FailedTransactionMetadata> {
48 let payer_pk = payer_kp.pubkey();
49 let buffer_kp = Keypair::new();
50 let buffer_pk = buffer_kp.pubkey();
51 let buffer_len = UpgradeableLoaderState::size_of_buffer(program_bytes.len());
53 let lamports = svm.minimum_balance_for_rent_exemption(buffer_len);
54
55 let tx = Transaction::new_signed_with_payer(
56 &bpf_loader_upgradeable::create_buffer(
57 &payer_pk,
58 &buffer_pk,
59 &payer_pk,
60 lamports,
61 program_bytes.len(),
62 )
63 .expect("Failed to create buffer instruction"),
64 Some(&payer_pk),
65 &[payer_kp, &buffer_kp],
66 svm.latest_blockhash(),
67 );
68
69 svm.send_transaction(tx)?;
70
71 let chunk_size = CHUNK_SIZE;
72 let mut offset = 0;
73 for chunk in program_bytes.chunks(chunk_size) {
74 let tx = Transaction::new_signed_with_payer(
75 &[bpf_loader_upgradeable::write(&buffer_pk, &payer_pk, offset, chunk.to_vec())],
76 Some(&payer_pk),
77 &[payer_kp],
78 svm.latest_blockhash(),
79 );
80
81 svm.send_transaction(tx)?;
82 offset += chunk_size as u32;
83 }
84
85 Ok(buffer_pk)
86}
87
88pub fn deploy_upgradeable_program(
90 svm: &mut HPSVM,
91 payer_kp: &Keypair,
92 program_kp: &Keypair,
93 program_bytes: &[u8],
94) -> Result<(), FailedTransactionMetadata> {
95 let program_pk = program_kp.pubkey();
96 let payer_pk = payer_kp.pubkey();
97 let buffer_pk = load_upgradeable_buffer(svm, payer_kp, program_bytes)?;
98
99 let lamports = svm.minimum_balance_for_rent_exemption(program_bytes.len());
100 let tx = Transaction::new_signed_with_payer(
101 &bpf_loader_upgradeable::deploy_with_max_program_len(
102 &payer_pk,
103 &program_pk,
104 &buffer_pk,
105 &payer_pk,
106 lamports,
107 program_bytes.len() * 2,
108 )
109 .expect("Failed to create deploy instruction"),
110 Some(&payer_pk),
111 &[&payer_kp, &program_kp],
112 svm.latest_blockhash(),
113 );
114
115 svm.send_transaction(tx)?;
116
117 Ok(())
118}