miraland_program/
bpf_loader_upgradeable.rs

1//! An upgradeable BPF loader native program.
2//!
3//! The upgradeable BPF loader is responsible for deploying, upgrading, and
4//! executing BPF programs. The upgradeable loader allows a program's authority
5//! to update the program at any time. This ability breaks the "code is law"
6//! contract that once a program is on-chain it is immutable. Because of this,
7//! care should be taken before executing upgradeable programs which still have
8//! a functioning authority. For more information refer to the
9//! [`loader_upgradeable_instruction`] module.
10//!
11//! The `solana program deploy` CLI command uses the
12//! upgradeable BPF loader. Calling `solana program deploy --final` deploys a
13//! program that cannot be upgraded, but it does so by revoking the authority to
14//! upgrade, not by using the non-upgradeable loader.
15//!
16//! [`loader_upgradeable_instruction`]: crate::loader_upgradeable_instruction
17
18use crate::{
19    instruction::{AccountMeta, Instruction, InstructionError},
20    loader_upgradeable_instruction::UpgradeableLoaderInstruction,
21    pubkey::Pubkey,
22    system_instruction, sysvar,
23};
24
25crate::declare_id!("BPFLoaderUpgradeab1e11111111111111111111111");
26
27/// Upgradeable loader account states
28#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, AbiExample)]
29pub enum UpgradeableLoaderState {
30    /// Account is not initialized.
31    Uninitialized,
32    /// A Buffer account.
33    Buffer {
34        /// Authority address
35        authority_address: Option<Pubkey>,
36        // The raw program data follows this serialized structure in the
37        // account's data.
38    },
39    /// An Program account.
40    Program {
41        /// Address of the ProgramData account.
42        programdata_address: Pubkey,
43    },
44    // A ProgramData account.
45    ProgramData {
46        /// Slot that the program was last modified.
47        slot: u64,
48        /// Address of the Program's upgrade authority.
49        upgrade_authority_address: Option<Pubkey>,
50        // The raw program data follows this serialized structure in the
51        // account's data.
52    },
53}
54impl UpgradeableLoaderState {
55    /// Size of a serialized program account.
56    pub const fn size_of_uninitialized() -> usize {
57        4 // see test_state_size_of_uninitialized
58    }
59
60    /// Size of a buffer account's serialized metadata.
61    pub const fn size_of_buffer_metadata() -> usize {
62        37 // see test_state_size_of_buffer_metadata
63    }
64
65    /// Size of a programdata account's serialized metadata.
66    pub const fn size_of_programdata_metadata() -> usize {
67        45 // see test_state_size_of_programdata_metadata
68    }
69
70    /// Size of a serialized program account.
71    pub const fn size_of_program() -> usize {
72        36 // see test_state_size_of_program
73    }
74
75    /// Size of a serialized buffer account.
76    pub const fn size_of_buffer(program_len: usize) -> usize {
77        Self::size_of_buffer_metadata().saturating_add(program_len)
78    }
79
80    /// Size of a serialized programdata account.
81    pub const fn size_of_programdata(program_len: usize) -> usize {
82        Self::size_of_programdata_metadata().saturating_add(program_len)
83    }
84
85    /// Length of a Buffer account's data.
86    #[deprecated(since = "1.11.0", note = "Please use `size_of_buffer` instead")]
87    pub fn buffer_len(program_len: usize) -> Result<usize, InstructionError> {
88        Ok(Self::size_of_buffer(program_len))
89    }
90
91    /// Offset into the Buffer account's data of the program bits.
92    #[deprecated(
93        since = "1.11.0",
94        note = "Please use `size_of_buffer_metadata` instead"
95    )]
96    pub fn buffer_data_offset() -> Result<usize, InstructionError> {
97        Ok(Self::size_of_buffer_metadata())
98    }
99
100    /// Length of a Program account's data.
101    #[deprecated(since = "1.11.0", note = "Please use `size_of_program` instead")]
102    pub fn program_len() -> Result<usize, InstructionError> {
103        Ok(Self::size_of_program())
104    }
105
106    /// Length of a ProgramData account's data.
107    #[deprecated(since = "1.11.0", note = "Please use `size_of_programdata` instead")]
108    pub fn programdata_len(program_len: usize) -> Result<usize, InstructionError> {
109        Ok(Self::size_of_programdata(program_len))
110    }
111
112    /// Offset into the ProgramData account's data of the program bits.
113    #[deprecated(
114        since = "1.11.0",
115        note = "Please use `size_of_programdata_metadata` instead"
116    )]
117    pub fn programdata_data_offset() -> Result<usize, InstructionError> {
118        Ok(Self::size_of_programdata_metadata())
119    }
120}
121
122/// Returns the program data address for a program ID
123pub fn get_program_data_address(program_address: &Pubkey) -> Pubkey {
124    Pubkey::find_program_address(&[program_address.as_ref()], &id()).0
125}
126
127/// Returns the instructions required to initialize a Buffer account.
128pub fn create_buffer(
129    payer_address: &Pubkey,
130    buffer_address: &Pubkey,
131    authority_address: &Pubkey,
132    lamports: u64,
133    program_len: usize,
134) -> Result<Vec<Instruction>, InstructionError> {
135    Ok(vec![
136        system_instruction::create_account(
137            payer_address,
138            buffer_address,
139            lamports,
140            UpgradeableLoaderState::size_of_buffer(program_len) as u64,
141            &id(),
142        ),
143        Instruction::new_with_bincode(
144            id(),
145            &UpgradeableLoaderInstruction::InitializeBuffer,
146            vec![
147                AccountMeta::new(*buffer_address, false),
148                AccountMeta::new_readonly(*authority_address, false),
149            ],
150        ),
151    ])
152}
153
154/// Returns the instructions required to write a chunk of program data to a
155/// buffer account.
156pub fn write(
157    buffer_address: &Pubkey,
158    authority_address: &Pubkey,
159    offset: u32,
160    bytes: Vec<u8>,
161) -> Instruction {
162    Instruction::new_with_bincode(
163        id(),
164        &UpgradeableLoaderInstruction::Write { offset, bytes },
165        vec![
166            AccountMeta::new(*buffer_address, false),
167            AccountMeta::new_readonly(*authority_address, true),
168        ],
169    )
170}
171
172/// Returns the instructions required to deploy a program with a specified
173/// maximum program length.  The maximum length must be large enough to
174/// accommodate any future upgrades.
175pub fn deploy_with_max_program_len(
176    payer_address: &Pubkey,
177    program_address: &Pubkey,
178    buffer_address: &Pubkey,
179    upgrade_authority_address: &Pubkey,
180    program_lamports: u64,
181    max_data_len: usize,
182) -> Result<Vec<Instruction>, InstructionError> {
183    let programdata_address = get_program_data_address(program_address);
184    Ok(vec![
185        system_instruction::create_account(
186            payer_address,
187            program_address,
188            program_lamports,
189            UpgradeableLoaderState::size_of_program() as u64,
190            &id(),
191        ),
192        Instruction::new_with_bincode(
193            id(),
194            &UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len },
195            vec![
196                AccountMeta::new(*payer_address, true),
197                AccountMeta::new(programdata_address, false),
198                AccountMeta::new(*program_address, false),
199                AccountMeta::new(*buffer_address, false),
200                AccountMeta::new_readonly(sysvar::rent::id(), false),
201                AccountMeta::new_readonly(sysvar::clock::id(), false),
202                AccountMeta::new_readonly(crate::system_program::id(), false),
203                AccountMeta::new_readonly(*upgrade_authority_address, true),
204            ],
205        ),
206    ])
207}
208
209/// Returns the instructions required to upgrade a program.
210pub fn upgrade(
211    program_address: &Pubkey,
212    buffer_address: &Pubkey,
213    authority_address: &Pubkey,
214    spill_address: &Pubkey,
215) -> Instruction {
216    let programdata_address = get_program_data_address(program_address);
217    Instruction::new_with_bincode(
218        id(),
219        &UpgradeableLoaderInstruction::Upgrade,
220        vec![
221            AccountMeta::new(programdata_address, false),
222            AccountMeta::new(*program_address, false),
223            AccountMeta::new(*buffer_address, false),
224            AccountMeta::new(*spill_address, false),
225            AccountMeta::new_readonly(sysvar::rent::id(), false),
226            AccountMeta::new_readonly(sysvar::clock::id(), false),
227            AccountMeta::new_readonly(*authority_address, true),
228        ],
229    )
230}
231
232pub fn is_upgrade_instruction(instruction_data: &[u8]) -> bool {
233    !instruction_data.is_empty() && 3 == instruction_data[0]
234}
235
236pub fn is_set_authority_instruction(instruction_data: &[u8]) -> bool {
237    !instruction_data.is_empty() && 4 == instruction_data[0]
238}
239
240pub fn is_close_instruction(instruction_data: &[u8]) -> bool {
241    !instruction_data.is_empty() && 5 == instruction_data[0]
242}
243
244pub fn is_set_authority_checked_instruction(instruction_data: &[u8]) -> bool {
245    !instruction_data.is_empty() && 7 == instruction_data[0]
246}
247
248/// Returns the instructions required to set a buffers's authority.
249pub fn set_buffer_authority(
250    buffer_address: &Pubkey,
251    current_authority_address: &Pubkey,
252    new_authority_address: &Pubkey,
253) -> Instruction {
254    Instruction::new_with_bincode(
255        id(),
256        &UpgradeableLoaderInstruction::SetAuthority,
257        vec![
258            AccountMeta::new(*buffer_address, false),
259            AccountMeta::new_readonly(*current_authority_address, true),
260            AccountMeta::new_readonly(*new_authority_address, false),
261        ],
262    )
263}
264
265/// Returns the instructions required to set a buffers's authority. If using this instruction, the new authority
266/// must sign.
267pub fn set_buffer_authority_checked(
268    buffer_address: &Pubkey,
269    current_authority_address: &Pubkey,
270    new_authority_address: &Pubkey,
271) -> Instruction {
272    Instruction::new_with_bincode(
273        id(),
274        &UpgradeableLoaderInstruction::SetAuthorityChecked,
275        vec![
276            AccountMeta::new(*buffer_address, false),
277            AccountMeta::new_readonly(*current_authority_address, true),
278            AccountMeta::new_readonly(*new_authority_address, true),
279        ],
280    )
281}
282
283/// Returns the instructions required to set a program's authority.
284pub fn set_upgrade_authority(
285    program_address: &Pubkey,
286    current_authority_address: &Pubkey,
287    new_authority_address: Option<&Pubkey>,
288) -> Instruction {
289    let programdata_address = get_program_data_address(program_address);
290
291    let mut metas = vec![
292        AccountMeta::new(programdata_address, false),
293        AccountMeta::new_readonly(*current_authority_address, true),
294    ];
295    if let Some(address) = new_authority_address {
296        metas.push(AccountMeta::new_readonly(*address, false));
297    }
298    Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::SetAuthority, metas)
299}
300
301/// Returns the instructions required to set a program's authority. If using this instruction, the new authority
302/// must sign.
303pub fn set_upgrade_authority_checked(
304    program_address: &Pubkey,
305    current_authority_address: &Pubkey,
306    new_authority_address: &Pubkey,
307) -> Instruction {
308    let programdata_address = get_program_data_address(program_address);
309
310    let metas = vec![
311        AccountMeta::new(programdata_address, false),
312        AccountMeta::new_readonly(*current_authority_address, true),
313        AccountMeta::new_readonly(*new_authority_address, true),
314    ];
315    Instruction::new_with_bincode(
316        id(),
317        &UpgradeableLoaderInstruction::SetAuthorityChecked,
318        metas,
319    )
320}
321
322/// Returns the instructions required to close a buffer account
323pub fn close(
324    close_address: &Pubkey,
325    recipient_address: &Pubkey,
326    authority_address: &Pubkey,
327) -> Instruction {
328    close_any(
329        close_address,
330        recipient_address,
331        Some(authority_address),
332        None,
333    )
334}
335
336/// Returns the instructions required to close program, buffer, or uninitialized account
337pub fn close_any(
338    close_address: &Pubkey,
339    recipient_address: &Pubkey,
340    authority_address: Option<&Pubkey>,
341    program_address: Option<&Pubkey>,
342) -> Instruction {
343    let mut metas = vec![
344        AccountMeta::new(*close_address, false),
345        AccountMeta::new(*recipient_address, false),
346    ];
347    if let Some(authority_address) = authority_address {
348        metas.push(AccountMeta::new_readonly(*authority_address, true));
349    }
350    if let Some(program_address) = program_address {
351        metas.push(AccountMeta::new(*program_address, false));
352    }
353    Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::Close, metas)
354}
355
356/// Returns the instruction required to extend the size of a program's
357/// executable data account
358pub fn extend_program(
359    program_address: &Pubkey,
360    payer_address: Option<&Pubkey>,
361    additional_bytes: u32,
362) -> Instruction {
363    let program_data_address = get_program_data_address(program_address);
364    let mut metas = vec![
365        AccountMeta::new(program_data_address, false),
366        AccountMeta::new(*program_address, false),
367    ];
368    if let Some(payer_address) = payer_address {
369        metas.push(AccountMeta::new_readonly(
370            crate::system_program::id(),
371            false,
372        ));
373        metas.push(AccountMeta::new(*payer_address, true));
374    }
375    Instruction::new_with_bincode(
376        id(),
377        &UpgradeableLoaderInstruction::ExtendProgram { additional_bytes },
378        metas,
379    )
380}
381
382#[cfg(test)]
383mod tests {
384    use {super::*, bincode::serialized_size};
385
386    #[test]
387    fn test_state_size_of_uninitialized() {
388        let buffer_state = UpgradeableLoaderState::Uninitialized;
389        let size = serialized_size(&buffer_state).unwrap();
390        assert_eq!(UpgradeableLoaderState::size_of_uninitialized() as u64, size);
391    }
392
393    #[test]
394    fn test_state_size_of_buffer_metadata() {
395        let buffer_state = UpgradeableLoaderState::Buffer {
396            authority_address: Some(Pubkey::default()),
397        };
398        let size = serialized_size(&buffer_state).unwrap();
399        assert_eq!(
400            UpgradeableLoaderState::size_of_buffer_metadata() as u64,
401            size
402        );
403    }
404
405    #[test]
406    fn test_state_size_of_programdata_metadata() {
407        let programdata_state = UpgradeableLoaderState::ProgramData {
408            upgrade_authority_address: Some(Pubkey::default()),
409            slot: 0,
410        };
411        let size = serialized_size(&programdata_state).unwrap();
412        assert_eq!(
413            UpgradeableLoaderState::size_of_programdata_metadata() as u64,
414            size
415        );
416    }
417
418    #[test]
419    fn test_state_size_of_program() {
420        let program_state = UpgradeableLoaderState::Program {
421            programdata_address: Pubkey::default(),
422        };
423        let size = serialized_size(&program_state).unwrap();
424        assert_eq!(UpgradeableLoaderState::size_of_program() as u64, size);
425    }
426
427    #[test]
428    #[allow(deprecated)]
429    fn test_account_lengths() {
430        assert_eq!(
431            4,
432            serialized_size(&UpgradeableLoaderState::Uninitialized).unwrap()
433        );
434        assert_eq!(36, UpgradeableLoaderState::program_len().unwrap());
435        assert_eq!(
436            45,
437            UpgradeableLoaderState::programdata_data_offset().unwrap()
438        );
439        assert_eq!(
440            45 + 42,
441            UpgradeableLoaderState::programdata_len(42).unwrap()
442        );
443    }
444
445    fn assert_is_instruction<F>(
446        is_instruction_fn: F,
447        expected_instruction: UpgradeableLoaderInstruction,
448    ) where
449        F: Fn(&[u8]) -> bool,
450    {
451        let result = is_instruction_fn(
452            &bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap(),
453        );
454        let expected_result = matches!(
455            expected_instruction,
456            UpgradeableLoaderInstruction::InitializeBuffer
457        );
458        assert_eq!(expected_result, result);
459
460        let result = is_instruction_fn(
461            &bincode::serialize(&UpgradeableLoaderInstruction::Write {
462                offset: 0,
463                bytes: vec![],
464            })
465            .unwrap(),
466        );
467        let expected_result = matches!(
468            expected_instruction,
469            UpgradeableLoaderInstruction::Write {
470                offset: _,
471                bytes: _,
472            }
473        );
474        assert_eq!(expected_result, result);
475
476        let result = is_instruction_fn(
477            &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
478                max_data_len: 0,
479            })
480            .unwrap(),
481        );
482        let expected_result = matches!(
483            expected_instruction,
484            UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len: _ }
485        );
486        assert_eq!(expected_result, result);
487
488        let result =
489            is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap());
490        let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Upgrade);
491        assert_eq!(expected_result, result);
492
493        let result = is_instruction_fn(
494            &bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap(),
495        );
496        let expected_result = matches!(
497            expected_instruction,
498            UpgradeableLoaderInstruction::SetAuthority
499        );
500        assert_eq!(expected_result, result);
501
502        let result =
503            is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap());
504        let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Close);
505        assert_eq!(expected_result, result);
506    }
507
508    #[test]
509    fn test_is_set_authority_instruction() {
510        assert!(!is_set_authority_instruction(&[]));
511        assert_is_instruction(
512            is_set_authority_instruction,
513            UpgradeableLoaderInstruction::SetAuthority {},
514        );
515    }
516
517    #[test]
518    fn test_is_set_authority_checked_instruction() {
519        assert!(!is_set_authority_checked_instruction(&[]));
520        assert_is_instruction(
521            is_set_authority_checked_instruction,
522            UpgradeableLoaderInstruction::SetAuthorityChecked {},
523        );
524    }
525
526    #[test]
527    fn test_is_upgrade_instruction() {
528        assert!(!is_upgrade_instruction(&[]));
529        assert_is_instruction(
530            is_upgrade_instruction,
531            UpgradeableLoaderInstruction::Upgrade {},
532        );
533    }
534}