solana_program_runtime/
deploy.rs1#[cfg(feature = "metrics")]
4use {crate::program_metrics::LoadProgramMetrics, solana_svm_measure::measure::Measure};
5use {
6 crate::{
7 invoke_context::InvokeContext,
8 loaded_programs::{ProgramCacheForTxBatch, ProgramRuntimeEnvironment},
9 program_cache_entry::{ProgramCacheEntry, ProgramCacheEntryOwner},
10 },
11 solana_clock::Slot,
12 solana_instruction_error::InstructionError,
13 solana_pubkey::Pubkey,
14 solana_sbpf::{
15 elf::{ElfError, Executable},
16 program::{BuiltinProgram, SBPFVersion},
17 verifier::RequisiteVerifier,
18 },
19 solana_svm_log_collector::{LogCollector, ic_logger_msg},
20 solana_svm_type_overrides::sync::Arc,
21 std::{cell::RefCell, rc::Rc},
22};
23
24pub fn morph_into_deployment_environment(
27 from: ProgramRuntimeEnvironment,
28 disable_sbpf_v0_v1_v2_deployment: bool,
29) -> Result<BuiltinProgram<InvokeContext<'static, 'static>>, ElfError> {
30 let mut config = (*from).get_config().clone();
31 config.reject_broken_elfs = true;
32 if disable_sbpf_v0_v1_v2_deployment {
33 config.enabled_sbpf_versions = SBPFVersion::V3..=*config.enabled_sbpf_versions.end();
34 }
35
36 let mut result = BuiltinProgram::new_loader(config);
37
38 for (_key, (name, value)) in (*from).get_function_registry().iter() {
39 if name != *b"sol_alloc_free_" {
41 result.register_function(unsafe { std::str::from_utf8_unchecked(name) }, value)?;
42 }
43 }
44
45 Ok(result)
46}
47
48#[allow(clippy::too_many_arguments)]
52pub fn deploy_program(
53 log_collector: Option<Rc<RefCell<LogCollector>>>,
54 #[cfg(feature = "metrics")] load_program_metrics: &mut LoadProgramMetrics,
55 program_cache_for_tx_batch: &mut ProgramCacheForTxBatch,
56 program_runtime_environment: ProgramRuntimeEnvironment,
57 disable_sbpf_v0_v1_v2_deployment: bool,
58 program_id: &Pubkey,
59 loader_key: &Pubkey,
60 programdata: &[u8],
61 deployment_slot: Slot,
62) -> Result<(), InstructionError> {
63 #[cfg(feature = "metrics")]
64 let mut register_syscalls_time = Measure::start("register_syscalls_time");
65 let deployment_program_runtime_environment = morph_into_deployment_environment(
66 ProgramRuntimeEnvironment::clone(&program_runtime_environment),
67 disable_sbpf_v0_v1_v2_deployment,
68 )
69 .map_err(|e| {
70 ic_logger_msg!(log_collector, "Failed to register syscalls: {}", e);
71 InstructionError::ProgramEnvironmentSetupFailure
72 })?;
73 #[cfg(feature = "metrics")]
74 {
75 register_syscalls_time.stop();
76 load_program_metrics.register_syscalls_us = register_syscalls_time.as_us();
77 }
78 #[cfg(feature = "metrics")]
80 let mut load_elf_time = Measure::start("load_elf_time");
81 let executable = Executable::<InvokeContext>::load(
82 programdata,
83 Arc::new(deployment_program_runtime_environment),
84 )
85 .map_err(|err| {
86 ic_logger_msg!(log_collector, "{}", err);
87 InstructionError::InvalidAccountData
88 })?;
89 #[cfg(feature = "metrics")]
90 {
91 load_elf_time.stop();
92 load_program_metrics.load_elf_us = load_elf_time.as_us();
93 }
94 #[cfg(feature = "metrics")]
95 let mut verify_code_time = Measure::start("verify_code_time");
96 executable.verify::<RequisiteVerifier>().map_err(|err| {
97 ic_logger_msg!(log_collector, "{}", err);
98 InstructionError::InvalidAccountData
99 })?;
100 #[cfg(feature = "metrics")]
101 {
102 verify_code_time.stop();
103 load_program_metrics.verify_code_us = verify_code_time.as_us();
104 }
105 let program_cache_entry = ProgramCacheEntry::new_unloaded(
107 deployment_slot,
108 ProgramCacheEntryOwner::try_from(loader_key)
109 .map_err(|_| InstructionError::InvalidAccountData)?,
110 program_runtime_environment,
111 );
112 if let Some(old_entry) = program_cache_for_tx_batch.find(program_id) {
113 program_cache_entry.stats.merge_from(&old_entry.stats);
114 }
115 #[cfg(feature = "metrics")]
116 {
117 load_program_metrics.program_id = program_id.to_string();
118 }
119 program_cache_for_tx_batch.store_modified_entry(*program_id, Arc::new(program_cache_entry));
120 Ok(())
121}
122
123#[macro_export]
124macro_rules! deploy_program {
125 ($invoke_context:expr,
126 $program_id:expr,
127 $loader_key:expr,
128 $programdata:expr,
129 $deployment_slot:expr,
130 $disable_sbpf_v0_v1_v2_deployment:expr $(,)?) => {
131 assert_eq!(
132 $deployment_slot,
133 $invoke_context.program_cache_for_tx_batch.slot()
134 );
135 #[cfg(feature = "metrics")]
136 let mut load_program_metrics = $crate::program_metrics::LoadProgramMetrics::default();
137 $crate::deploy::deploy_program(
138 $invoke_context.get_log_collector(),
139 #[cfg(feature = "metrics")]
140 &mut load_program_metrics,
141 $invoke_context.program_cache_for_tx_batch,
142 $invoke_context
143 .get_program_runtime_environment_for_deployment()
144 .clone(),
145 $disable_sbpf_v0_v1_v2_deployment,
146 $program_id,
147 $loader_key,
148 $programdata,
149 $deployment_slot,
150 )?;
151 #[cfg(feature = "metrics")]
152 load_program_metrics.submit_datapoint(&mut $invoke_context.timings);
153 };
154}