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