1#[cfg(feature = "bincode")]
3use {
4 solana_instruction::{AccountMeta, Instruction},
5 solana_pubkey::Pubkey,
6 solana_sdk_ids::loader_v4::id,
7};
8
9#[repr(u8)]
10#[cfg_attr(
11 feature = "serde",
12 derive(serde_derive::Deserialize, serde_derive::Serialize)
13)]
14#[derive(Debug, PartialEq, Eq, Clone)]
15pub enum LoaderV4Instruction {
16 Write {
22 offset: u32,
24 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
26 bytes: Vec<u8>,
27 },
28
29 Copy {
36 destination_offset: u32,
38 source_offset: u32,
40 length: u32,
42 },
43
44 SetProgramLength {
58 new_size: u32,
60 },
61
62 Deploy,
75
76 Retract,
85
86 TransferAuthority,
93
94 Finalize,
101}
102
103pub fn is_write_instruction(instruction_data: &[u8]) -> bool {
104 !instruction_data.is_empty() && 0 == instruction_data[0]
105}
106
107pub fn is_copy_instruction(instruction_data: &[u8]) -> bool {
108 !instruction_data.is_empty() && 1 == instruction_data[0]
109}
110
111pub fn is_set_program_length_instruction(instruction_data: &[u8]) -> bool {
112 !instruction_data.is_empty() && 2 == instruction_data[0]
113}
114
115pub fn is_deploy_instruction(instruction_data: &[u8]) -> bool {
116 !instruction_data.is_empty() && 3 == instruction_data[0]
117}
118
119pub fn is_retract_instruction(instruction_data: &[u8]) -> bool {
120 !instruction_data.is_empty() && 4 == instruction_data[0]
121}
122
123pub fn is_transfer_authority_instruction(instruction_data: &[u8]) -> bool {
124 !instruction_data.is_empty() && 5 == instruction_data[0]
125}
126
127pub fn is_finalize_instruction(instruction_data: &[u8]) -> bool {
128 !instruction_data.is_empty() && 6 == instruction_data[0]
129}
130
131#[cfg(feature = "bincode")]
133pub fn create_buffer(
134 payer_address: &Pubkey,
135 buffer_address: &Pubkey,
136 lamports: u64,
137 authority: &Pubkey,
138 new_size: u32,
139 recipient_address: &Pubkey,
140) -> Vec<Instruction> {
141 vec![
142 solana_system_interface::instruction::create_account(
143 payer_address,
144 buffer_address,
145 lamports,
146 0,
147 &id(),
148 ),
149 set_program_length(buffer_address, authority, new_size, recipient_address),
150 ]
151}
152
153#[cfg(feature = "bincode")]
155pub fn set_program_length(
156 program_address: &Pubkey,
157 authority: &Pubkey,
158 new_size: u32,
159 recipient_address: &Pubkey,
160) -> Instruction {
161 Instruction::new_with_bincode(
162 id(),
163 &LoaderV4Instruction::SetProgramLength { new_size },
164 vec![
165 AccountMeta::new(*program_address, false),
166 AccountMeta::new_readonly(*authority, true),
167 AccountMeta::new(*recipient_address, false),
168 ],
169 )
170}
171
172#[cfg(feature = "bincode")]
175pub fn write(
176 program_address: &Pubkey,
177 authority: &Pubkey,
178 offset: u32,
179 bytes: Vec<u8>,
180) -> Instruction {
181 Instruction::new_with_bincode(
182 id(),
183 &LoaderV4Instruction::Write { offset, bytes },
184 vec![
185 AccountMeta::new(*program_address, false),
186 AccountMeta::new_readonly(*authority, true),
187 ],
188 )
189}
190
191#[cfg(feature = "bincode")]
193pub fn copy(
194 program_address: &Pubkey,
195 authority: &Pubkey,
196 source_address: &Pubkey,
197 destination_offset: u32,
198 source_offset: u32,
199 length: u32,
200) -> Instruction {
201 Instruction::new_with_bincode(
202 id(),
203 &LoaderV4Instruction::Copy {
204 destination_offset,
205 source_offset,
206 length,
207 },
208 vec![
209 AccountMeta::new(*program_address, false),
210 AccountMeta::new_readonly(*authority, true),
211 AccountMeta::new_readonly(*source_address, false),
212 ],
213 )
214}
215
216#[cfg(feature = "bincode")]
218pub fn deploy(program_address: &Pubkey, authority: &Pubkey) -> Instruction {
219 Instruction::new_with_bincode(
220 id(),
221 &LoaderV4Instruction::Deploy,
222 vec![
223 AccountMeta::new(*program_address, false),
224 AccountMeta::new_readonly(*authority, true),
225 ],
226 )
227}
228
229#[cfg(feature = "bincode")]
231pub fn deploy_from_source(
232 program_address: &Pubkey,
233 authority: &Pubkey,
234 source_address: &Pubkey,
235) -> Instruction {
236 Instruction::new_with_bincode(
237 id(),
238 &LoaderV4Instruction::Deploy,
239 vec![
240 AccountMeta::new(*program_address, false),
241 AccountMeta::new_readonly(*authority, true),
242 AccountMeta::new(*source_address, false),
243 ],
244 )
245}
246
247#[cfg(feature = "bincode")]
249pub fn retract(program_address: &Pubkey, authority: &Pubkey) -> Instruction {
250 Instruction::new_with_bincode(
251 id(),
252 &LoaderV4Instruction::Retract,
253 vec![
254 AccountMeta::new(*program_address, false),
255 AccountMeta::new_readonly(*authority, true),
256 ],
257 )
258}
259
260#[cfg(feature = "bincode")]
262pub fn transfer_authority(
263 program_address: &Pubkey,
264 authority: &Pubkey,
265 new_authority: &Pubkey,
266) -> Instruction {
267 let accounts = vec![
268 AccountMeta::new(*program_address, false),
269 AccountMeta::new_readonly(*authority, true),
270 AccountMeta::new_readonly(*new_authority, true),
271 ];
272
273 Instruction::new_with_bincode(id(), &LoaderV4Instruction::TransferAuthority, accounts)
274}
275
276#[cfg(feature = "bincode")]
278pub fn finalize(
279 program_address: &Pubkey,
280 authority: &Pubkey,
281 next_version_program_address: &Pubkey,
282) -> Instruction {
283 let accounts = vec![
284 AccountMeta::new(*program_address, false),
285 AccountMeta::new_readonly(*authority, true),
286 AccountMeta::new_readonly(*next_version_program_address, false),
287 ];
288
289 Instruction::new_with_bincode(id(), &LoaderV4Instruction::Finalize, accounts)
290}
291
292#[cfg(test)]
293mod tests {
294 use {super::*, solana_sdk_ids::system_program};
295
296 #[test]
297 fn test_create_buffer_instruction() {
298 let payer = Pubkey::new_unique();
299 let program = Pubkey::new_unique();
300 let authority = Pubkey::new_unique();
301 let recipient = Pubkey::new_unique();
302 let instructions = create_buffer(&payer, &program, 123, &authority, 10, &recipient);
303 assert_eq!(instructions.len(), 2);
304 let instruction0 = &instructions[0];
305 assert_eq!(instruction0.program_id, system_program::id());
306 assert_eq!(instruction0.accounts.len(), 2);
307 assert_eq!(instruction0.accounts[0].pubkey, payer);
308 assert!(instruction0.accounts[0].is_writable);
309 assert!(instruction0.accounts[0].is_signer);
310 assert_eq!(instruction0.accounts[1].pubkey, program);
311 assert!(instruction0.accounts[1].is_writable);
312 assert!(instruction0.accounts[1].is_signer);
313
314 let instruction1 = &instructions[1];
315 assert!(is_set_program_length_instruction(&instruction1.data));
316 assert_eq!(instruction1.program_id, id());
317 assert_eq!(instruction1.accounts.len(), 3);
318 assert_eq!(instruction1.accounts[0].pubkey, program);
319 assert!(instruction1.accounts[0].is_writable);
320 assert!(!instruction1.accounts[0].is_signer);
321 assert_eq!(instruction1.accounts[1].pubkey, authority);
322 assert!(!instruction1.accounts[1].is_writable);
323 assert!(instruction1.accounts[1].is_signer);
324 assert_eq!(instruction1.accounts[2].pubkey, recipient);
325 assert!(instruction1.accounts[2].is_writable);
326 assert!(!instruction1.accounts[2].is_signer);
327 }
328
329 #[test]
330 fn test_write_instruction() {
331 let program = Pubkey::new_unique();
332 let authority = Pubkey::new_unique();
333 let instruction = write(&program, &authority, 123, vec![1, 2, 3, 4]);
334 assert!(is_write_instruction(&instruction.data));
335 assert_eq!(instruction.program_id, id());
336 assert_eq!(instruction.accounts.len(), 2);
337 assert_eq!(instruction.accounts[0].pubkey, program);
338 assert!(instruction.accounts[0].is_writable);
339 assert!(!instruction.accounts[0].is_signer);
340 assert_eq!(instruction.accounts[1].pubkey, authority);
341 assert!(!instruction.accounts[1].is_writable);
342 assert!(instruction.accounts[1].is_signer);
343 }
344
345 #[test]
346 fn test_copy_instruction() {
347 let program = Pubkey::new_unique();
348 let authority = Pubkey::new_unique();
349 let source = Pubkey::new_unique();
350 let instruction = copy(&program, &authority, &source, 1, 2, 3);
351 assert!(is_copy_instruction(&instruction.data));
352 assert_eq!(instruction.program_id, id());
353 assert_eq!(instruction.accounts.len(), 3);
354 assert_eq!(instruction.accounts[0].pubkey, program);
355 assert!(instruction.accounts[0].is_writable);
356 assert!(!instruction.accounts[0].is_signer);
357 assert_eq!(instruction.accounts[1].pubkey, authority);
358 assert!(!instruction.accounts[1].is_writable);
359 assert!(instruction.accounts[1].is_signer);
360 assert_eq!(instruction.accounts[2].pubkey, source);
361 assert!(!instruction.accounts[2].is_writable);
362 assert!(!instruction.accounts[2].is_signer);
363 }
364
365 #[test]
366 fn test_set_program_length_instruction() {
367 let program = Pubkey::new_unique();
368 let authority = Pubkey::new_unique();
369 let recipient = Pubkey::new_unique();
370 let instruction = set_program_length(&program, &authority, 10, &recipient);
371 assert!(is_set_program_length_instruction(&instruction.data));
372 assert_eq!(instruction.program_id, id());
373 assert_eq!(instruction.accounts.len(), 3);
374 assert_eq!(instruction.accounts[0].pubkey, program);
375 assert!(instruction.accounts[0].is_writable);
376 assert!(!instruction.accounts[0].is_signer);
377 assert_eq!(instruction.accounts[1].pubkey, authority);
378 assert!(!instruction.accounts[1].is_writable);
379 assert!(instruction.accounts[1].is_signer);
380 assert_eq!(instruction.accounts[2].pubkey, recipient);
381 assert!(instruction.accounts[2].is_writable);
382 assert!(!instruction.accounts[2].is_signer);
383 }
384
385 #[test]
386 fn test_deploy_instruction() {
387 let program = Pubkey::new_unique();
388 let authority = Pubkey::new_unique();
389 let instruction = deploy(&program, &authority);
390 assert!(is_deploy_instruction(&instruction.data));
391 assert_eq!(instruction.program_id, id());
392 assert_eq!(instruction.accounts.len(), 2);
393 assert_eq!(instruction.accounts[0].pubkey, program);
394 assert!(instruction.accounts[0].is_writable);
395 assert!(!instruction.accounts[0].is_signer);
396 assert_eq!(instruction.accounts[1].pubkey, authority);
397 assert!(!instruction.accounts[1].is_writable);
398 assert!(instruction.accounts[1].is_signer);
399 }
400
401 #[test]
402 fn test_deploy_from_source_instruction() {
403 let program = Pubkey::new_unique();
404 let authority = Pubkey::new_unique();
405 let source = Pubkey::new_unique();
406 let instruction = deploy_from_source(&program, &authority, &source);
407 assert!(is_deploy_instruction(&instruction.data));
408 assert_eq!(instruction.program_id, id());
409 assert_eq!(instruction.accounts.len(), 3);
410 assert_eq!(instruction.accounts[0].pubkey, program);
411 assert!(instruction.accounts[0].is_writable);
412 assert!(!instruction.accounts[0].is_signer);
413 assert_eq!(instruction.accounts[1].pubkey, authority);
414 assert!(!instruction.accounts[1].is_writable);
415 assert!(instruction.accounts[1].is_signer);
416 assert_eq!(instruction.accounts[2].pubkey, source);
417 assert!(instruction.accounts[2].is_writable);
418 assert!(!instruction.accounts[2].is_signer);
419 }
420
421 #[test]
422 fn test_retract_instruction() {
423 let program = Pubkey::new_unique();
424 let authority = Pubkey::new_unique();
425 let instruction = retract(&program, &authority);
426 assert!(is_retract_instruction(&instruction.data));
427 assert_eq!(instruction.program_id, id());
428 assert_eq!(instruction.accounts.len(), 2);
429 assert_eq!(instruction.accounts[0].pubkey, program);
430 assert!(instruction.accounts[0].is_writable);
431 assert!(!instruction.accounts[0].is_signer);
432 assert_eq!(instruction.accounts[1].pubkey, authority);
433 assert!(!instruction.accounts[1].is_writable);
434 assert!(instruction.accounts[1].is_signer);
435 }
436
437 #[test]
438 fn test_transfer_authority_instruction() {
439 let program = Pubkey::new_unique();
440 let authority = Pubkey::new_unique();
441 let new_authority = Pubkey::new_unique();
442 let instruction = transfer_authority(&program, &authority, &new_authority);
443 assert!(is_transfer_authority_instruction(&instruction.data));
444 assert_eq!(instruction.program_id, id());
445 assert_eq!(instruction.accounts.len(), 3);
446 assert_eq!(instruction.accounts[0].pubkey, program);
447 assert!(instruction.accounts[0].is_writable);
448 assert!(!instruction.accounts[0].is_signer);
449 assert_eq!(instruction.accounts[1].pubkey, authority);
450 assert!(!instruction.accounts[1].is_writable);
451 assert!(instruction.accounts[1].is_signer);
452 assert_eq!(instruction.accounts[2].pubkey, new_authority);
453 assert!(!instruction.accounts[2].is_writable);
454 assert!(instruction.accounts[2].is_signer);
455 }
456
457 #[test]
458 fn test_transfer_authority_finalize_instruction() {
459 let program = Pubkey::new_unique();
460 let authority = Pubkey::new_unique();
461 let next_version = Pubkey::new_unique();
462 let instruction = finalize(&program, &authority, &next_version);
463 assert!(is_finalize_instruction(&instruction.data));
464 assert_eq!(instruction.program_id, id());
465 assert_eq!(instruction.accounts.len(), 3);
466 assert_eq!(instruction.accounts[0].pubkey, program);
467 assert!(instruction.accounts[0].is_writable);
468 assert!(!instruction.accounts[0].is_signer);
469 assert_eq!(instruction.accounts[1].pubkey, authority);
470 assert!(!instruction.accounts[1].is_writable);
471 assert!(instruction.accounts[1].is_signer);
472 assert_eq!(instruction.accounts[2].pubkey, next_version);
473 assert!(!instruction.accounts[2].is_writable);
474 assert!(!instruction.accounts[2].is_signer);
475 }
476}