1pub mod abort;
2pub mod crypto;
3pub mod log;
4pub mod memory;
5pub mod pda;
6pub mod return_data;
7pub mod sysvar;
8
9use {
10 crate::{
11 config::{ExecutionCost, SysvarContext},
12 cpi::request::{self, CpiRequest},
13 runtime::LogCollector,
14 },
15 sbpf_vm::{
16 compute::ComputeMeter, errors::SbpfVmResult, memory::Memory, syscalls::SyscallHandler,
17 },
18 solana_address::Address,
19};
20
21const ACCOUNT_META_SIZE: u64 = 34;
22const ACCOUNT_INFO_BYTE_SIZE: u64 = 80;
23
24pub struct RuntimeSyscallHandler {
25 pub costs: ExecutionCost,
26 pub program_id: Address,
27 pub sysvars: SysvarContext,
28 pub pending_cpi: Option<CpiRequest>,
29 pub return_data: crate::cpi::ReturnData,
30 pub log_collector: LogCollector,
31}
32
33impl RuntimeSyscallHandler {
34 pub fn new(
35 costs: ExecutionCost,
36 program_id: Address,
37 sysvars: SysvarContext,
38 log_collector: LogCollector,
39 ) -> Self {
40 Self {
41 costs,
42 program_id,
43 sysvars,
44 pending_cpi: None,
45 return_data: None,
46 log_collector,
47 }
48 }
49}
50
51fn consume_cpi_compute_units(
53 request: &CpiRequest,
54 compute: &ComputeMeter,
55 costs: &ExecutionCost,
56) -> SbpfVmResult<()> {
57 compute.consume(costs.invoke_units)?;
59
60 let data_cost = request.data.len() as u64 / costs.cpi_bytes_per_unit;
62 let meta_cost = (request.accounts.len() as u64 * ACCOUNT_META_SIZE) / costs.cpi_bytes_per_unit;
63 compute.consume(data_cost + meta_cost)?;
64
65 let account_info_cost =
67 (request.caller_accounts.len() as u64 * ACCOUNT_INFO_BYTE_SIZE) / costs.cpi_bytes_per_unit;
68 compute.consume(account_info_cost)?;
69
70 let mut seen = Vec::with_capacity(request.accounts.len());
72 for meta in request.accounts.iter() {
73 if seen.contains(&meta.pubkey) {
74 continue;
75 }
76 seen.push(meta.pubkey);
77 if let Some(caller) = request
78 .caller_accounts
79 .iter()
80 .find(|c| c.pubkey == meta.pubkey)
81 {
82 let acct_cost = caller.data_len / costs.cpi_bytes_per_unit;
83 compute.consume(acct_cost)?;
84 }
85 }
86 Ok(())
87}
88
89impl SyscallHandler for RuntimeSyscallHandler {
90 fn handle(
91 &mut self,
92 name: &str,
93 registers: [u64; 5],
94 memory: &mut Memory,
95 compute: ComputeMeter,
96 ) -> SbpfVmResult<u64> {
97 match name {
98 "sol_log_" => log::sol_log(
99 registers,
100 memory,
101 &compute,
102 &self.costs,
103 &self.log_collector,
104 ),
105 "sol_log_64_" => log::sol_log_64(registers, &compute, &self.costs, &self.log_collector),
106 "sol_log_pubkey" => log::sol_log_pubkey(
107 registers,
108 memory,
109 &compute,
110 &self.costs,
111 &self.log_collector,
112 ),
113 "sol_log_compute_units_" => {
114 log::sol_log_compute_units(&compute, &self.costs, &self.log_collector)
115 }
116 "sol_remaining_compute_units" => {
117 log::sol_remaining_compute_units(&compute, &self.costs)
118 }
119
120 "sol_memcpy_" => memory::sol_memcpy(registers, memory, &compute, &self.costs),
121 "sol_memmove_" => memory::sol_memmove(registers, memory, &compute, &self.costs),
122 "sol_memset_" => memory::sol_memset(registers, memory, &compute, &self.costs),
123 "sol_memcmp_" => memory::sol_memcmp(registers, memory, &compute, &self.costs),
124
125 "abort" => abort::abort(),
126 "sol_panic_" => abort::sol_panic(registers, memory),
127
128 "sol_sha256" => crypto::sol_sha256(registers, memory, &compute, &self.costs),
129 "sol_keccak256" => crypto::sol_keccak256(registers, memory, &compute, &self.costs),
130 "sol_blake3" => crypto::sol_blake3(registers, memory, &compute, &self.costs),
131
132 "sol_create_program_address" => {
133 pda::sol_create_program_address(registers, memory, &compute, &self.costs)
134 }
135 "sol_try_find_program_address" => {
136 pda::sol_try_find_program_address(registers, memory, &compute, &self.costs)
137 }
138
139 "sol_get_clock_sysvar" => sysvar::sol_get_clock_sysvar(
140 registers,
141 memory,
142 &compute,
143 &self.costs,
144 &self.sysvars,
145 ),
146 "sol_get_rent_sysvar" => {
147 sysvar::sol_get_rent_sysvar(registers, memory, &compute, &self.costs, &self.sysvars)
148 }
149 "sol_get_epoch_schedule_sysvar" => sysvar::sol_get_epoch_schedule_sysvar(
150 registers,
151 memory,
152 &compute,
153 &self.costs,
154 &self.sysvars,
155 ),
156 "sol_get_last_restart_slot_sysvar" => sysvar::sol_get_last_restart_slot_sysvar(
157 registers,
158 memory,
159 &compute,
160 &self.costs,
161 &self.sysvars,
162 ),
163
164 "sol_set_return_data" => {
165 let (result, data) = return_data::sol_set_return_data(
166 registers,
167 memory,
168 &compute,
169 &self.costs,
170 &self.program_id,
171 )?;
172 self.return_data = data;
173 Ok(result)
174 }
175 "sol_get_return_data" => return_data::sol_get_return_data(
176 registers,
177 memory,
178 &compute,
179 &self.costs,
180 &self.return_data,
181 ),
182
183 "sol_invoke_signed_c" => {
184 let request = request::parse_cpi_c(registers, memory, &self.program_id)?;
185 consume_cpi_compute_units(&request, &compute, &self.costs)?;
186 self.pending_cpi = Some(request);
187 Ok(0)
188 }
189 "sol_invoke_signed_rust" => {
190 let request = request::parse_cpi_rust(registers, memory, &self.program_id)?;
191 consume_cpi_compute_units(&request, &compute, &self.costs)?;
192 self.pending_cpi = Some(request);
193 Ok(0)
194 }
195
196 _ => {
197 compute.consume(self.costs.syscall_base_cost)?;
198 eprintln!("Unknown syscall: {}", name);
199 Ok(0)
200 }
201 }
202 }
203}