gemachain_runtime/
loader_utils.rs

1use serde::Serialize;
2use gemachain_sdk::{
3    bpf_loader_upgradeable::{self, UpgradeableLoaderState},
4    client::Client,
5    instruction::{AccountMeta, Instruction},
6    loader_instruction,
7    message::Message,
8    pubkey::Pubkey,
9    signature::{Keypair, Signer},
10    system_instruction,
11};
12
13pub fn load_program<T: Client>(
14    bank_client: &T,
15    from_keypair: &Keypair,
16    loader_pubkey: &Pubkey,
17    program: Vec<u8>,
18) -> Pubkey {
19    let program_keypair = Keypair::new();
20    let program_pubkey = program_keypair.pubkey();
21
22    let instruction = system_instruction::create_account(
23        &from_keypair.pubkey(),
24        &program_pubkey,
25        1.max(
26            bank_client
27                .get_minimum_balance_for_rent_exemption(program.len())
28                .unwrap(),
29        ),
30        program.len() as u64,
31        loader_pubkey,
32    );
33    bank_client
34        .send_and_confirm_message(
35            &[from_keypair, &program_keypair],
36            Message::new(&[instruction], Some(&from_keypair.pubkey())),
37        )
38        .unwrap();
39
40    let chunk_size = 256; // Size of chunk just needs to fit into tx
41    let mut offset = 0;
42    for chunk in program.chunks(chunk_size) {
43        let instruction =
44            loader_instruction::write(&program_pubkey, loader_pubkey, offset, chunk.to_vec());
45        let message = Message::new(&[instruction], Some(&from_keypair.pubkey()));
46        bank_client
47            .send_and_confirm_message(&[from_keypair, &program_keypair], message)
48            .unwrap();
49        offset += chunk_size as u32;
50    }
51
52    let instruction = loader_instruction::finalize(&program_pubkey, loader_pubkey);
53    let message = Message::new(&[instruction], Some(&from_keypair.pubkey()));
54    bank_client
55        .send_and_confirm_message(&[from_keypair, &program_keypair], message)
56        .unwrap();
57
58    program_pubkey
59}
60
61pub fn load_buffer_account<T: Client>(
62    bank_client: &T,
63    from_keypair: &Keypair,
64    buffer_keypair: &Keypair,
65    buffer_authority_keypair: &Keypair,
66    program: &[u8],
67) {
68    let buffer_pubkey = buffer_keypair.pubkey();
69    let buffer_authority_pubkey = buffer_authority_keypair.pubkey();
70
71    bank_client
72        .send_and_confirm_message(
73            &[from_keypair, buffer_keypair],
74            Message::new(
75                &bpf_loader_upgradeable::create_buffer(
76                    &from_keypair.pubkey(),
77                    &buffer_pubkey,
78                    &buffer_authority_pubkey,
79                    1.max(
80                        bank_client
81                            .get_minimum_balance_for_rent_exemption(program.len())
82                            .unwrap(),
83                    ),
84                    program.len(),
85                )
86                .unwrap(),
87                Some(&from_keypair.pubkey()),
88            ),
89        )
90        .unwrap();
91
92    let chunk_size = 256; // Size of chunk just needs to fit into tx
93    let mut offset = 0;
94    for chunk in program.chunks(chunk_size) {
95        let message = Message::new(
96            &[bpf_loader_upgradeable::write(
97                &buffer_pubkey,
98                &buffer_authority_pubkey,
99                offset,
100                chunk.to_vec(),
101            )],
102            Some(&from_keypair.pubkey()),
103        );
104        bank_client
105            .send_and_confirm_message(&[from_keypair, buffer_authority_keypair], message)
106            .unwrap();
107        offset += chunk_size as u32;
108    }
109}
110
111pub fn load_upgradeable_program<T: Client>(
112    bank_client: &T,
113    from_keypair: &Keypair,
114    buffer_keypair: &Keypair,
115    executable_keypair: &Keypair,
116    authority_keypair: &Keypair,
117    program: Vec<u8>,
118) {
119    let program_pubkey = executable_keypair.pubkey();
120    let authority_pubkey = authority_keypair.pubkey();
121
122    load_buffer_account(
123        bank_client,
124        from_keypair,
125        buffer_keypair,
126        authority_keypair,
127        &program,
128    );
129
130    let message = Message::new(
131        &bpf_loader_upgradeable::deploy_with_max_program_len(
132            &from_keypair.pubkey(),
133            &program_pubkey,
134            &buffer_keypair.pubkey(),
135            &authority_pubkey,
136            1.max(
137                bank_client
138                    .get_minimum_balance_for_rent_exemption(
139                        UpgradeableLoaderState::program_len().unwrap(),
140                    )
141                    .unwrap(),
142            ),
143            program.len() * 2,
144        )
145        .unwrap(),
146        Some(&from_keypair.pubkey()),
147    );
148    bank_client
149        .send_and_confirm_message(
150            &[from_keypair, executable_keypair, authority_keypair],
151            message,
152        )
153        .unwrap();
154}
155
156pub fn upgrade_program<T: Client>(
157    bank_client: &T,
158    from_keypair: &Keypair,
159    program_pubkey: &Pubkey,
160    buffer_pubkey: &Pubkey,
161    authority_keypair: &Keypair,
162    spill_pubkey: &Pubkey,
163) {
164    let message = Message::new(
165        &[bpf_loader_upgradeable::upgrade(
166            program_pubkey,
167            buffer_pubkey,
168            &authority_keypair.pubkey(),
169            spill_pubkey,
170        )],
171        Some(&from_keypair.pubkey()),
172    );
173    bank_client
174        .send_and_confirm_message(&[from_keypair, authority_keypair], message)
175        .unwrap();
176}
177
178pub fn set_upgrade_authority<T: Client>(
179    bank_client: &T,
180    from_keypair: &Keypair,
181    program_pubkey: &Pubkey,
182    current_authority_keypair: &Keypair,
183    new_authority_pubkey: Option<&Pubkey>,
184) {
185    let message = Message::new(
186        &[bpf_loader_upgradeable::set_upgrade_authority(
187            program_pubkey,
188            &current_authority_keypair.pubkey(),
189            new_authority_pubkey,
190        )],
191        Some(&from_keypair.pubkey()),
192    );
193    bank_client
194        .send_and_confirm_message(&[from_keypair, current_authority_keypair], message)
195        .unwrap();
196}
197
198// Return an Instruction that invokes `program_id` with `data` and required
199// a signature from `from_pubkey`.
200pub fn create_invoke_instruction<T: Serialize>(
201    from_pubkey: Pubkey,
202    program_id: Pubkey,
203    data: &T,
204) -> Instruction {
205    let account_metas = vec![AccountMeta::new(from_pubkey, true)];
206    Instruction::new_with_bincode(program_id, data, account_metas)
207}