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::{DELAY_VISIBILITY_SLOT_OFFSET, ProgramCacheEntry},
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
24fn morph_into_deployment_environment(
25 from: ProgramRuntimeEnvironment,
26 disable_sbpf_v0_v1_v2_deployment: bool,
27) -> Result<BuiltinProgram<InvokeContext<'static, 'static>>, ElfError> {
28 let mut config = (*from).get_config().clone();
29 config.reject_broken_elfs = true;
30 if disable_sbpf_v0_v1_v2_deployment {
31 config.enabled_sbpf_versions = SBPFVersion::V3..=*config.enabled_sbpf_versions.end();
32 }
33
34 let mut result = BuiltinProgram::new_loader(config);
35
36 for (_key, (name, value)) in (*from).get_function_registry().iter() {
37 if name != *b"sol_alloc_free_" {
39 result.register_function(unsafe { std::str::from_utf8_unchecked(name) }, value)?;
40 }
41 }
42
43 Ok(result)
44}
45
46#[allow(clippy::too_many_arguments)]
50pub fn deploy_program(
51 log_collector: Option<Rc<RefCell<LogCollector>>>,
52 #[cfg(feature = "metrics")] load_program_metrics: &mut LoadProgramMetrics,
53 program_cache_for_tx_batch: &mut ProgramCacheForTxBatch,
54 program_runtime_environment: ProgramRuntimeEnvironment,
55 disable_sbpf_v0_v1_v2_deployment: bool,
56 program_id: &Pubkey,
57 loader_key: &Pubkey,
58 account_size: usize,
59 programdata: &[u8],
60 deployment_slot: Slot,
61) -> Result<(), InstructionError> {
62 #[cfg(feature = "metrics")]
63 let mut register_syscalls_time = Measure::start("register_syscalls_time");
64 let deployment_program_runtime_environment = morph_into_deployment_environment(
65 ProgramRuntimeEnvironment::clone(&program_runtime_environment),
66 disable_sbpf_v0_v1_v2_deployment,
67 )
68 .map_err(|e| {
69 ic_logger_msg!(log_collector, "Failed to register syscalls: {}", e);
70 InstructionError::ProgramEnvironmentSetupFailure
71 })?;
72 #[cfg(feature = "metrics")]
73 {
74 register_syscalls_time.stop();
75 load_program_metrics.register_syscalls_us = register_syscalls_time.as_us();
76 }
77 #[cfg(feature = "metrics")]
79 let mut load_elf_time = Measure::start("load_elf_time");
80 let executable = Executable::<InvokeContext>::load(
81 programdata,
82 Arc::new(deployment_program_runtime_environment),
83 )
84 .map_err(|err| {
85 ic_logger_msg!(log_collector, "{}", err);
86 InstructionError::InvalidAccountData
87 })?;
88 #[cfg(feature = "metrics")]
89 {
90 load_elf_time.stop();
91 load_program_metrics.load_elf_us = load_elf_time.as_us();
92 }
93 #[cfg(feature = "metrics")]
94 let mut verify_code_time = Measure::start("verify_code_time");
95 executable.verify::<RequisiteVerifier>().map_err(|err| {
96 ic_logger_msg!(log_collector, "{}", err);
97 InstructionError::InvalidAccountData
98 })?;
99 #[cfg(feature = "metrics")]
100 {
101 verify_code_time.stop();
102 load_program_metrics.verify_code_us = verify_code_time.as_us();
103 }
104 let executor = unsafe {
106 ProgramCacheEntry::reload(
108 loader_key,
109 program_runtime_environment,
110 deployment_slot,
111 deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET),
112 programdata,
113 account_size,
114 #[cfg(feature = "metrics")]
115 load_program_metrics,
116 )
117 }
118 .map_err(|err| {
119 ic_logger_msg!(log_collector, "{}", err);
120 InstructionError::InvalidAccountData
121 })?;
122 if let Some(old_entry) = program_cache_for_tx_batch.find(program_id) {
123 executor.stats.merge_from(&old_entry.stats);
124 }
125 #[cfg(feature = "metrics")]
126 {
127 load_program_metrics.program_id = program_id.to_string();
128 }
129 program_cache_for_tx_batch.store_modified_entry(*program_id, Arc::new(executor));
130 Ok(())
131}
132
133#[macro_export]
134macro_rules! deploy_program {
135 ($invoke_context:expr,
136 $program_id:expr,
137 $loader_key:expr,
138 $account_size:expr,
139 $programdata:expr,
140 $deployment_slot:expr,
141 $disable_sbpf_v0_v1_v2_deployment:expr $(,)?) => {
142 assert_eq!(
143 $deployment_slot,
144 $invoke_context.program_cache_for_tx_batch.slot()
145 );
146 #[cfg(feature = "metrics")]
147 let mut load_program_metrics = $crate::program_metrics::LoadProgramMetrics::default();
148 $crate::deploy::deploy_program(
149 $invoke_context.get_log_collector(),
150 #[cfg(feature = "metrics")]
151 &mut load_program_metrics,
152 $invoke_context.program_cache_for_tx_batch,
153 $invoke_context
154 .get_program_runtime_environment_for_deployment()
155 .clone(),
156 $disable_sbpf_v0_v1_v2_deployment,
157 $program_id,
158 $loader_key,
159 $account_size,
160 $programdata,
161 $deployment_slot,
162 )?;
163 #[cfg(feature = "metrics")]
164 load_program_metrics.submit_datapoint(&mut $invoke_context.timings);
165 };
166}