rpc_process.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. use {
  2. crate::svm_bridge::{
  3. create_executable_environment, LoadAndExecuteTransactionsOutput, MockBankCallback,
  4. MockForkGraph, TransactionBatch,
  5. },
  6. base64::{prelude::BASE64_STANDARD, Engine},
  7. bincode::config::Options,
  8. jsonrpc_core::{types::error, Error, Metadata, Result},
  9. jsonrpc_derive::rpc,
  10. log::*,
  11. serde_json,
  12. solana_account_decoder::{
  13. encode_ui_account,
  14. parse_account_data::{AccountAdditionalDataV2, SplTokenAdditionalData},
  15. parse_token::{get_token_account_mint, is_known_spl_token_id},
  16. UiAccount, UiAccountEncoding, UiDataSliceConfig, MAX_BASE58_BYTES,
  17. },
  18. solana_compute_budget::compute_budget::ComputeBudget,
  19. solana_perf::packet::PACKET_DATA_SIZE,
  20. solana_program_runtime::loaded_programs::ProgramCacheEntry,
  21. solana_rpc_client_api::{
  22. config::*,
  23. response::{Response as RpcResponse, *},
  24. },
  25. solana_sdk::{
  26. account::{from_account, Account, AccountSharedData, ReadableAccount},
  27. clock::{Slot, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY},
  28. commitment_config::CommitmentConfig,
  29. exit::Exit,
  30. hash::Hash,
  31. inner_instruction::InnerInstructions,
  32. message::{
  33. v0::{LoadedAddresses, MessageAddressTableLookup},
  34. AddressLoaderError,
  35. },
  36. nonce::state::DurableNonce,
  37. pubkey::Pubkey,
  38. reserved_account_keys::ReservedAccountKeys,
  39. signature::Signature,
  40. system_instruction, sysvar,
  41. transaction::{
  42. AddressLoader, MessageHash, SanitizedTransaction, TransactionError,
  43. VersionedTransaction,
  44. },
  45. transaction_context::{TransactionAccount, TransactionReturnData},
  46. },
  47. solana_svm::{
  48. account_loader::{CheckedTransactionDetails, TransactionCheckResult},
  49. account_overrides::AccountOverrides,
  50. transaction_error_metrics::TransactionErrorMetrics,
  51. transaction_processing_result::{
  52. ProcessedTransaction, TransactionProcessingResultExtensions,
  53. },
  54. transaction_processor::{
  55. ExecutionRecordingConfig, TransactionBatchProcessor, TransactionLogMessages,
  56. TransactionProcessingConfig, TransactionProcessingEnvironment,
  57. },
  58. },
  59. solana_system_program::system_processor,
  60. solana_transaction_status::{
  61. map_inner_instructions, parse_ui_inner_instructions, TransactionBinaryEncoding,
  62. UiTransactionEncoding,
  63. },
  64. spl_token_2022::{
  65. extension::{
  66. interest_bearing_mint::InterestBearingConfig, BaseStateWithExtensions,
  67. StateWithExtensions,
  68. },
  69. state::Mint,
  70. },
  71. std::{
  72. any::type_name,
  73. cmp::min,
  74. collections::{HashMap, HashSet},
  75. fs,
  76. path::PathBuf,
  77. str::FromStr,
  78. sync::{
  79. atomic::{AtomicBool, Ordering},
  80. Arc, RwLock,
  81. },
  82. },
  83. };
  84. pub const MAX_REQUEST_BODY_SIZE: usize = 50 * (1 << 10); // 50kB
  85. const EXECUTION_SLOT: u64 = 5; // The execution slot must be greater than the deployment slot
  86. const EXECUTION_EPOCH: u64 = 2; // The execution epoch must be greater than the deployment epoch
  87. const MAX_BASE58_SIZE: usize = 1683; // Golden, bump if PACKET_DATA_SIZE changes
  88. const MAX_BASE64_SIZE: usize = 1644; // Golden, bump if PACKET_DATA_SIZE changes
  89. fn new_response<T>(slot: Slot, value: T) -> RpcResponse<T> {
  90. RpcResponse {
  91. context: RpcResponseContext::new(slot),
  92. value,
  93. }
  94. }
  95. #[derive(Debug, Default, Clone)]
  96. pub struct JsonRpcConfig {
  97. pub accounts_path: PathBuf,
  98. pub ledger_path: PathBuf,
  99. pub rpc_threads: usize,
  100. pub rpc_niceness_adj: i8,
  101. pub max_request_body_size: Option<usize>,
  102. }
  103. #[derive(Clone)]
  104. pub struct JsonRpcRequestProcessor {
  105. account_map: Vec<(Pubkey, AccountSharedData)>,
  106. #[allow(dead_code)]
  107. exit: Arc<RwLock<Exit>>,
  108. transaction_processor: Arc<RwLock<TransactionBatchProcessor<MockForkGraph>>>,
  109. }
  110. struct TransactionSimulationResult {
  111. pub result: solana_sdk::transaction::Result<()>,
  112. pub logs: TransactionLogMessages,
  113. pub post_simulation_accounts: Vec<TransactionAccount>,
  114. pub units_consumed: u64,
  115. pub return_data: Option<TransactionReturnData>,
  116. pub inner_instructions: Option<Vec<InnerInstructions>>,
  117. }
  118. #[derive(Debug, Default, PartialEq)]
  119. pub struct ProcessedTransactionCounts {
  120. pub processed_transactions_count: u64,
  121. pub processed_non_vote_transactions_count: u64,
  122. pub processed_with_successful_result_count: u64,
  123. pub signature_count: u64,
  124. }
  125. #[derive(Debug, PartialEq, Eq)]
  126. pub enum TransactionLogCollectorFilter {
  127. All,
  128. AllWithVotes,
  129. None,
  130. OnlyMentionedAddresses,
  131. }
  132. impl Default for TransactionLogCollectorFilter {
  133. fn default() -> Self {
  134. Self::None
  135. }
  136. }
  137. #[derive(Debug, Default)]
  138. pub struct TransactionLogCollectorConfig {
  139. pub mentioned_addresses: HashSet<Pubkey>,
  140. pub filter: TransactionLogCollectorFilter,
  141. }
  142. #[derive(Clone, Debug, PartialEq, Eq)]
  143. pub struct TransactionLogInfo {
  144. pub signature: Signature,
  145. pub result: solana_sdk::transaction::Result<()>,
  146. pub is_vote: bool,
  147. pub log_messages: TransactionLogMessages,
  148. }
  149. #[derive(Default, Debug)]
  150. pub struct TransactionLogCollector {
  151. // All the logs collected for from this Bank. Exact contents depend on the
  152. // active `TransactionLogCollectorFilter`
  153. pub logs: Vec<TransactionLogInfo>,
  154. // For each `mentioned_addresses`, maintain a list of indices into `logs` to easily
  155. // locate the logs from transactions that included the mentioned addresses.
  156. pub mentioned_address_map: HashMap<Pubkey, Vec<usize>>,
  157. }
  158. impl AddressLoader for JsonRpcRequestProcessor {
  159. fn load_addresses(
  160. self,
  161. _lookups: &[MessageAddressTableLookup],
  162. ) -> core::result::Result<LoadedAddresses, AddressLoaderError> {
  163. Ok(LoadedAddresses {
  164. writable: vec![],
  165. readonly: vec![],
  166. })
  167. }
  168. }
  169. impl Metadata for JsonRpcRequestProcessor {}
  170. impl JsonRpcRequestProcessor {
  171. pub fn new(config: JsonRpcConfig, exit: Arc<RwLock<Exit>>) -> Self {
  172. let accounts_json_path = config.accounts_path.clone();
  173. let accounts_data: String = fs::read_to_string(accounts_json_path).unwrap();
  174. let accounts_data: serde_json::Value = serde_json::from_str(&accounts_data).unwrap();
  175. let accounts_slice: Vec<(Pubkey, AccountSharedData)> = accounts_data["accounts"]
  176. .as_array()
  177. .unwrap()
  178. .iter()
  179. .map(|acc| {
  180. let pubkey = Pubkey::from_str(acc["pubkey"].as_str().unwrap()).unwrap();
  181. let account = acc["account"].as_object().unwrap();
  182. let owner = account["owner"].as_str().unwrap();
  183. let data = account["data"].as_array().unwrap()[0].as_str().unwrap();
  184. let acc_data = AccountSharedData::from(Account {
  185. lamports: account["lamports"].as_u64().unwrap(),
  186. data: BASE64_STANDARD.decode(data).unwrap(),
  187. owner: Pubkey::from_str(owner).unwrap(),
  188. executable: account["executable"].as_bool().unwrap(),
  189. rent_epoch: account["rentEpoch"].as_u64().unwrap(),
  190. });
  191. (pubkey, acc_data)
  192. })
  193. .collect();
  194. let batch_processor = TransactionBatchProcessor::<MockForkGraph>::new_uninitialized(
  195. EXECUTION_SLOT,
  196. EXECUTION_EPOCH,
  197. );
  198. Self {
  199. account_map: accounts_slice,
  200. exit,
  201. transaction_processor: Arc::new(RwLock::new(batch_processor)),
  202. }
  203. }
  204. fn get_account_info(
  205. &self,
  206. pubkey: &Pubkey,
  207. config: Option<RpcAccountInfoConfig>,
  208. ) -> Result<RpcResponse<Option<UiAccount>>> {
  209. let RpcAccountInfoConfig {
  210. encoding,
  211. data_slice,
  212. commitment: _,
  213. min_context_slot: _,
  214. } = config.unwrap_or_default();
  215. let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
  216. Ok(new_response(
  217. 0,
  218. match self.get_account(pubkey) {
  219. Some(account) => {
  220. debug!("Found account {pubkey:?}");
  221. Some(encode_account(&account, pubkey, encoding, data_slice)?)
  222. }
  223. None => {
  224. debug!("Did not find account {pubkey:?}");
  225. None
  226. }
  227. },
  228. ))
  229. }
  230. fn get_latest_blockhash(&self, _config: RpcContextConfig) -> Result<RpcResponse<RpcBlockhash>> {
  231. let blockhash = Hash::default();
  232. let last_valid_block_height = 0u64;
  233. Ok(new_response(
  234. 0,
  235. RpcBlockhash {
  236. blockhash: blockhash.to_string(),
  237. last_valid_block_height,
  238. },
  239. ))
  240. }
  241. fn get_minimum_balance_for_rent_exemption(
  242. &self,
  243. _data_len: usize,
  244. _commitment: Option<CommitmentConfig>,
  245. ) -> u64 {
  246. 0u64
  247. }
  248. fn simulate_transaction_unchecked(
  249. &self,
  250. transaction: &SanitizedTransaction,
  251. enable_cpi_recording: bool,
  252. ) -> TransactionSimulationResult {
  253. let mut mock_bank = MockBankCallback::new(self.account_map.clone());
  254. let transaction_processor = self.transaction_processor.read().unwrap();
  255. let account_keys = transaction.message().account_keys();
  256. let number_of_accounts = account_keys.len();
  257. let account_overrides = AccountOverrides::default();
  258. let fork_graph = Arc::new(RwLock::new(MockForkGraph {}));
  259. create_executable_environment(
  260. fork_graph.clone(),
  261. &account_keys,
  262. &mut mock_bank,
  263. &transaction_processor,
  264. );
  265. // Add the system program builtin.
  266. transaction_processor.add_builtin(
  267. &mock_bank,
  268. solana_system_program::id(),
  269. "system_program",
  270. ProgramCacheEntry::new_builtin(
  271. 0,
  272. b"system_program".len(),
  273. system_processor::Entrypoint::vm,
  274. ),
  275. );
  276. // Add the BPF Loader v2 builtin, for the SPL Token program.
  277. transaction_processor.add_builtin(
  278. &mock_bank,
  279. solana_sdk::bpf_loader_upgradeable::id(),
  280. "solana_bpf_loader_upgradeable_program",
  281. ProgramCacheEntry::new_builtin(
  282. 0,
  283. b"solana_bpf_loader_upgradeable_program".len(),
  284. solana_bpf_loader_program::Entrypoint::vm,
  285. ),
  286. );
  287. let batch = self.prepare_unlocked_batch_from_single_tx(transaction);
  288. let LoadAndExecuteTransactionsOutput {
  289. mut processing_results,
  290. ..
  291. } = self.load_and_execute_transactions(
  292. &mock_bank,
  293. &batch,
  294. // After simulation, transactions will need to be forwarded to the leader
  295. // for processing. During forwarding, the transaction could expire if the
  296. // delay is not accounted for.
  297. MAX_PROCESSING_AGE - MAX_TRANSACTION_FORWARDING_DELAY,
  298. TransactionProcessingConfig {
  299. account_overrides: Some(&account_overrides),
  300. check_program_modification_slot: false,
  301. compute_budget: Some(ComputeBudget::default()),
  302. log_messages_bytes_limit: None,
  303. limit_to_load_programs: true,
  304. recording_config: ExecutionRecordingConfig {
  305. enable_cpi_recording,
  306. enable_log_recording: true,
  307. enable_return_data_recording: true,
  308. },
  309. transaction_account_lock_limit: Some(64),
  310. },
  311. );
  312. let processing_result = processing_results
  313. .pop()
  314. .unwrap_or(Err(TransactionError::InvalidProgramForExecution));
  315. let flattened_result = processing_result.flattened_result();
  316. let (post_simulation_accounts, logs, return_data, inner_instructions) =
  317. match processing_result {
  318. Ok(processed_tx) => match processed_tx {
  319. ProcessedTransaction::Executed(executed_tx) => {
  320. let details = executed_tx.execution_details;
  321. let post_simulation_accounts = executed_tx
  322. .loaded_transaction
  323. .accounts
  324. .into_iter()
  325. .take(number_of_accounts)
  326. .collect::<Vec<_>>();
  327. (
  328. post_simulation_accounts,
  329. details.log_messages,
  330. details.return_data,
  331. details.inner_instructions,
  332. )
  333. }
  334. ProcessedTransaction::FeesOnly(_) => (vec![], None, None, None),
  335. },
  336. Err(_) => (vec![], None, None, None),
  337. };
  338. let logs = logs.unwrap_or_default();
  339. let units_consumed: u64 = 0;
  340. TransactionSimulationResult {
  341. result: flattened_result,
  342. logs,
  343. post_simulation_accounts,
  344. units_consumed,
  345. return_data,
  346. inner_instructions,
  347. }
  348. }
  349. fn prepare_unlocked_batch_from_single_tx<'a>(
  350. &'a self,
  351. transaction: &'a SanitizedTransaction,
  352. ) -> TransactionBatch<'a> {
  353. let tx_account_lock_limit = solana_sdk::transaction::MAX_TX_ACCOUNT_LOCKS;
  354. let lock_result = transaction
  355. .get_account_locks(tx_account_lock_limit)
  356. .map(|_| ());
  357. let batch = TransactionBatch::new(
  358. vec![lock_result],
  359. std::borrow::Cow::Borrowed(std::slice::from_ref(transaction)),
  360. );
  361. batch
  362. }
  363. fn check_age(
  364. &self,
  365. sanitized_txs: &[impl core::borrow::Borrow<SanitizedTransaction>],
  366. lock_results: &[solana_sdk::transaction::Result<()>],
  367. max_age: usize,
  368. error_counters: &mut TransactionErrorMetrics,
  369. ) -> Vec<TransactionCheckResult> {
  370. let last_blockhash = Hash::default();
  371. let next_durable_nonce = DurableNonce::from_blockhash(&last_blockhash);
  372. sanitized_txs
  373. .iter()
  374. .zip(lock_results)
  375. .map(|(tx, lock_res)| match lock_res {
  376. Ok(()) => self.check_transaction_age(
  377. tx.borrow(),
  378. max_age,
  379. &next_durable_nonce,
  380. error_counters,
  381. ),
  382. Err(e) => Err(e.clone()),
  383. })
  384. .collect()
  385. }
  386. fn check_transaction_age(
  387. &self,
  388. _tx: &SanitizedTransaction,
  389. _max_age: usize,
  390. _next_durable_nonce: &DurableNonce,
  391. _error_counters: &mut TransactionErrorMetrics,
  392. ) -> TransactionCheckResult {
  393. /* for now just return defaults */
  394. Ok(CheckedTransactionDetails {
  395. nonce: None,
  396. lamports_per_signature: u64::default(),
  397. })
  398. }
  399. fn clock(&self) -> sysvar::clock::Clock {
  400. from_account(&self.get_account(&sysvar::clock::id()).unwrap_or_default())
  401. .unwrap_or_default()
  402. }
  403. fn get_account(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
  404. let account_map: HashMap<Pubkey, AccountSharedData> =
  405. HashMap::from_iter(self.account_map.clone());
  406. account_map.get(pubkey).cloned()
  407. }
  408. fn get_additional_mint_data(&self, data: &[u8]) -> Result<SplTokenAdditionalData> {
  409. StateWithExtensions::<Mint>::unpack(data)
  410. .map_err(|_| {
  411. Error::invalid_params("Invalid param: Token mint could not be unpacked".to_string())
  412. })
  413. .map(|mint| {
  414. let interest_bearing_config = mint
  415. .get_extension::<InterestBearingConfig>()
  416. .map(|x| (*x, self.clock().unix_timestamp))
  417. .ok();
  418. SplTokenAdditionalData {
  419. decimals: mint.base.decimals,
  420. interest_bearing_config,
  421. }
  422. })
  423. }
  424. fn get_encoded_account(
  425. &self,
  426. pubkey: &Pubkey,
  427. encoding: UiAccountEncoding,
  428. data_slice: Option<UiDataSliceConfig>,
  429. // only used for simulation results
  430. overwrite_accounts: Option<&HashMap<Pubkey, AccountSharedData>>,
  431. ) -> Result<Option<UiAccount>> {
  432. match overwrite_accounts
  433. .and_then(|accounts| accounts.get(pubkey).cloned())
  434. .or_else(|| self.get_account(pubkey))
  435. {
  436. Some(account) => {
  437. let response = if is_known_spl_token_id(account.owner())
  438. && encoding == UiAccountEncoding::JsonParsed
  439. {
  440. self.get_parsed_token_account(pubkey, account, overwrite_accounts)
  441. } else {
  442. encode_account(&account, pubkey, encoding, data_slice)?
  443. };
  444. Ok(Some(response))
  445. }
  446. None => Ok(None),
  447. }
  448. }
  449. fn get_parsed_token_account(
  450. &self,
  451. pubkey: &Pubkey,
  452. account: AccountSharedData,
  453. // only used for simulation results
  454. overwrite_accounts: Option<&HashMap<Pubkey, AccountSharedData>>,
  455. ) -> UiAccount {
  456. let additional_data = get_token_account_mint(account.data())
  457. .and_then(|mint_pubkey| {
  458. overwrite_accounts
  459. .and_then(|accounts| accounts.get(&mint_pubkey).cloned())
  460. .or_else(|| self.get_account(&mint_pubkey))
  461. })
  462. .and_then(|mint_account| self.get_additional_mint_data(mint_account.data()).ok())
  463. .map(|data| AccountAdditionalDataV2 {
  464. spl_token_additional_data: Some(data),
  465. });
  466. encode_ui_account(
  467. pubkey,
  468. &account,
  469. UiAccountEncoding::JsonParsed,
  470. additional_data,
  471. None,
  472. )
  473. }
  474. fn last_blockhash_and_lamports_per_signature(&self) -> (Hash, u64) {
  475. let last_hash = Hash::default();
  476. let last_lamports_per_signature = u64::default();
  477. (last_hash, last_lamports_per_signature)
  478. }
  479. fn load_and_execute_transactions(
  480. &self,
  481. bank: &MockBankCallback,
  482. batch: &TransactionBatch,
  483. max_age: usize,
  484. processing_config: TransactionProcessingConfig,
  485. ) -> LoadAndExecuteTransactionsOutput {
  486. let sanitized_txs = batch.sanitized_transactions();
  487. debug!("processing transactions: {}", sanitized_txs.len());
  488. let mut error_counters = TransactionErrorMetrics::default();
  489. let check_results = self.check_age(
  490. sanitized_txs,
  491. batch.lock_results(),
  492. max_age,
  493. &mut error_counters,
  494. );
  495. let (blockhash, lamports_per_signature) = self.last_blockhash_and_lamports_per_signature();
  496. let processing_environment = TransactionProcessingEnvironment {
  497. blockhash,
  498. blockhash_lamports_per_signature: lamports_per_signature,
  499. epoch_total_stake: 0,
  500. feature_set: Arc::clone(&bank.feature_set),
  501. fee_lamports_per_signature: lamports_per_signature,
  502. rent_collector: None,
  503. };
  504. let sanitized_output = self
  505. .transaction_processor
  506. .read()
  507. .unwrap()
  508. .load_and_execute_sanitized_transactions(
  509. bank,
  510. sanitized_txs,
  511. check_results,
  512. &processing_environment,
  513. &processing_config,
  514. );
  515. let err_count = &mut error_counters.total;
  516. let mut processed_counts = ProcessedTransactionCounts::default();
  517. for (processing_result, tx) in sanitized_output
  518. .processing_results
  519. .iter()
  520. .zip(sanitized_txs)
  521. {
  522. if processing_result.was_processed() {
  523. // Signature count must be accumulated only if the transaction
  524. // is processed, otherwise a mismatched count between banking
  525. // and replay could occur
  526. processed_counts.signature_count +=
  527. u64::from(tx.message().header().num_required_signatures);
  528. processed_counts.processed_transactions_count += 1;
  529. if !tx.is_simple_vote_transaction() {
  530. processed_counts.processed_non_vote_transactions_count += 1;
  531. }
  532. }
  533. match processing_result.flattened_result() {
  534. Ok(()) => {
  535. processed_counts.processed_with_successful_result_count += 1;
  536. }
  537. Err(err) => {
  538. if *err_count == 0 {
  539. debug!("tx error: {:?} {:?}", err, tx);
  540. }
  541. *err_count += 1;
  542. }
  543. }
  544. }
  545. LoadAndExecuteTransactionsOutput {
  546. processing_results: sanitized_output.processing_results,
  547. }
  548. }
  549. }
  550. /// RPC interface that an API node is expected to provide
  551. pub mod rpc {
  552. use super::*;
  553. #[rpc]
  554. pub trait Rpc {
  555. type Metadata;
  556. #[rpc(meta, name = "getAccountInfo")]
  557. fn get_account_info(
  558. &self,
  559. meta: Self::Metadata,
  560. pubkey_str: String,
  561. config: Option<RpcAccountInfoConfig>,
  562. ) -> Result<RpcResponse<Option<UiAccount>>>;
  563. #[rpc(meta, name = "getLatestBlockhash")]
  564. fn get_latest_blockhash(
  565. &self,
  566. meta: Self::Metadata,
  567. config: Option<RpcContextConfig>,
  568. ) -> Result<RpcResponse<RpcBlockhash>>;
  569. #[rpc(meta, name = "getMinimumBalanceForRentExemption")]
  570. fn get_minimum_balance_for_rent_exemption(
  571. &self,
  572. meta: Self::Metadata,
  573. data_len: usize,
  574. commitment: Option<CommitmentConfig>,
  575. ) -> Result<u64>;
  576. #[rpc(meta, name = "getVersion")]
  577. fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
  578. #[rpc(meta, name = "simulateTransaction")]
  579. fn simulate_transaction(
  580. &self,
  581. meta: Self::Metadata,
  582. data: String,
  583. config: Option<RpcSimulateTransactionConfig>,
  584. ) -> Result<RpcResponse<RpcSimulateTransactionResult>>;
  585. }
  586. pub struct RpcImpl;
  587. impl Rpc for RpcImpl {
  588. type Metadata = JsonRpcRequestProcessor;
  589. fn simulate_transaction(
  590. &self,
  591. meta: Self::Metadata,
  592. data: String,
  593. config: Option<RpcSimulateTransactionConfig>,
  594. ) -> Result<RpcResponse<RpcSimulateTransactionResult>> {
  595. debug!("simulate_transaction rpc request received");
  596. let RpcSimulateTransactionConfig {
  597. sig_verify: _,
  598. replace_recent_blockhash: _,
  599. commitment: _,
  600. encoding,
  601. accounts: config_accounts,
  602. min_context_slot: _,
  603. inner_instructions: enable_cpi_recording,
  604. } = config.unwrap_or_default();
  605. let tx_encoding = encoding.unwrap_or(UiTransactionEncoding::Base58);
  606. let binary_encoding = tx_encoding.into_binary_encoding().ok_or_else(|| {
  607. Error::invalid_params(format!(
  608. "unsupported encoding: {tx_encoding}. Supported encodings: base58, base64"
  609. ))
  610. })?;
  611. let (_, unsanitized_tx) =
  612. decode_and_deserialize::<VersionedTransaction>(data, binary_encoding)?;
  613. debug!("unsanitized transaction decoded {:?}", unsanitized_tx);
  614. let transaction = sanitize_transaction(
  615. unsanitized_tx,
  616. meta.clone(),
  617. &ReservedAccountKeys::default().active,
  618. )?;
  619. let TransactionSimulationResult {
  620. result,
  621. logs,
  622. post_simulation_accounts,
  623. units_consumed,
  624. return_data,
  625. inner_instructions,
  626. } = meta.simulate_transaction_unchecked(&transaction, enable_cpi_recording);
  627. let account_keys = transaction.message().account_keys();
  628. let number_of_accounts = account_keys.len();
  629. let accounts = if let Some(config_accounts) = config_accounts {
  630. let accounts_encoding = config_accounts
  631. .encoding
  632. .unwrap_or(UiAccountEncoding::Base64);
  633. if accounts_encoding == UiAccountEncoding::Binary
  634. || accounts_encoding == UiAccountEncoding::Base58
  635. {
  636. return Err(Error::invalid_params("base58 encoding not supported"));
  637. }
  638. if config_accounts.addresses.len() > number_of_accounts {
  639. return Err(Error::invalid_params(format!(
  640. "Too many accounts provided; max {number_of_accounts}"
  641. )));
  642. }
  643. if result.is_err() {
  644. Some(vec![None; config_accounts.addresses.len()])
  645. } else {
  646. let mut post_simulation_accounts_map = HashMap::new();
  647. for (pubkey, data) in post_simulation_accounts {
  648. post_simulation_accounts_map.insert(pubkey, data);
  649. }
  650. Some(
  651. config_accounts
  652. .addresses
  653. .iter()
  654. .map(|address_str| {
  655. let pubkey = verify_pubkey(address_str)?;
  656. meta.get_encoded_account(
  657. &pubkey,
  658. accounts_encoding,
  659. None,
  660. Some(&post_simulation_accounts_map),
  661. )
  662. })
  663. .collect::<Result<Vec<_>>>()?,
  664. )
  665. }
  666. } else {
  667. None
  668. };
  669. let inner_instructions = inner_instructions.map(|info| {
  670. map_inner_instructions(info)
  671. .map(|converted| parse_ui_inner_instructions(converted, &account_keys))
  672. .collect()
  673. });
  674. Ok(new_response(
  675. 0,
  676. RpcSimulateTransactionResult {
  677. err: result.err(),
  678. logs: Some(logs),
  679. accounts,
  680. units_consumed: Some(units_consumed),
  681. return_data: return_data.map(|return_data| return_data.into()),
  682. inner_instructions,
  683. replacement_blockhash: None,
  684. },
  685. ))
  686. }
  687. fn get_account_info(
  688. &self,
  689. meta: Self::Metadata,
  690. pubkey_str: String,
  691. config: Option<RpcAccountInfoConfig>,
  692. ) -> Result<RpcResponse<Option<UiAccount>>> {
  693. debug!("get_account_info rpc request received: {:?}", pubkey_str);
  694. let pubkey = verify_pubkey(&pubkey_str)?;
  695. debug!("pubkey {pubkey:?} verified.");
  696. meta.get_account_info(&pubkey, config)
  697. }
  698. fn get_latest_blockhash(
  699. &self,
  700. meta: Self::Metadata,
  701. config: Option<RpcContextConfig>,
  702. ) -> Result<RpcResponse<RpcBlockhash>> {
  703. debug!("get_latest_blockhash rpc request received");
  704. meta.get_latest_blockhash(config.unwrap_or_default())
  705. }
  706. fn get_minimum_balance_for_rent_exemption(
  707. &self,
  708. meta: Self::Metadata,
  709. data_len: usize,
  710. commitment: Option<CommitmentConfig>,
  711. ) -> Result<u64> {
  712. debug!(
  713. "get_minimum_balance_for_rent_exemption rpc request received: {:?}",
  714. data_len
  715. );
  716. if data_len as u64 > system_instruction::MAX_PERMITTED_DATA_LENGTH {
  717. return Err(Error::invalid_request());
  718. }
  719. Ok(meta.get_minimum_balance_for_rent_exemption(data_len, commitment))
  720. }
  721. fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
  722. debug!("get_version rpc request received");
  723. let version = solana_version::Version::default();
  724. Ok(RpcVersionInfo {
  725. solana_core: version.to_string(),
  726. feature_set: Some(version.feature_set),
  727. })
  728. }
  729. }
  730. }
  731. pub fn create_exit(exit: Arc<AtomicBool>) -> Arc<RwLock<Exit>> {
  732. let mut exit_handler = Exit::default();
  733. exit_handler.register_exit(Box::new(move || exit.store(true, Ordering::Relaxed)));
  734. Arc::new(RwLock::new(exit_handler))
  735. }
  736. fn decode_and_deserialize<T>(
  737. encoded: String,
  738. encoding: TransactionBinaryEncoding,
  739. ) -> Result<(Vec<u8>, T)>
  740. where
  741. T: serde::de::DeserializeOwned,
  742. {
  743. let wire_output = match encoding {
  744. TransactionBinaryEncoding::Base58 => {
  745. if encoded.len() > MAX_BASE58_SIZE {
  746. return Err(Error::invalid_params(format!(
  747. "base58 encoded {} too large: {} bytes (max: encoded/raw {}/{})",
  748. type_name::<T>(),
  749. encoded.len(),
  750. MAX_BASE58_SIZE,
  751. PACKET_DATA_SIZE,
  752. )));
  753. }
  754. bs58::decode(encoded)
  755. .into_vec()
  756. .map_err(|e| Error::invalid_params(format!("invalid base58 encoding: {e:?}")))?
  757. }
  758. TransactionBinaryEncoding::Base64 => {
  759. if encoded.len() > MAX_BASE64_SIZE {
  760. return Err(Error::invalid_params(format!(
  761. "base64 encoded {} too large: {} bytes (max: encoded/raw {}/{})",
  762. type_name::<T>(),
  763. encoded.len(),
  764. MAX_BASE64_SIZE,
  765. PACKET_DATA_SIZE,
  766. )));
  767. }
  768. BASE64_STANDARD
  769. .decode(encoded)
  770. .map_err(|e| Error::invalid_params(format!("invalid base64 encoding: {e:?}")))?
  771. }
  772. };
  773. if wire_output.len() > PACKET_DATA_SIZE {
  774. return Err(Error::invalid_params(format!(
  775. "decoded {} too large: {} bytes (max: {} bytes)",
  776. type_name::<T>(),
  777. wire_output.len(),
  778. PACKET_DATA_SIZE
  779. )));
  780. }
  781. bincode::options()
  782. .with_limit(PACKET_DATA_SIZE as u64)
  783. .with_fixint_encoding()
  784. .allow_trailing_bytes()
  785. .deserialize_from(&wire_output[..])
  786. .map_err(|err| {
  787. Error::invalid_params(format!(
  788. "failed to deserialize {}: {}",
  789. type_name::<T>(),
  790. &err.to_string()
  791. ))
  792. })
  793. .map(|output| (wire_output, output))
  794. }
  795. fn encode_account<T: ReadableAccount>(
  796. account: &T,
  797. pubkey: &Pubkey,
  798. encoding: UiAccountEncoding,
  799. data_slice: Option<UiDataSliceConfig>,
  800. ) -> Result<UiAccount> {
  801. if (encoding == UiAccountEncoding::Binary || encoding == UiAccountEncoding::Base58)
  802. && data_slice
  803. .map(|s| min(s.length, account.data().len().saturating_sub(s.offset)))
  804. .unwrap_or(account.data().len())
  805. > MAX_BASE58_BYTES
  806. {
  807. let message = format!("Encoded binary (base 58) data should be less than {MAX_BASE58_BYTES} bytes, please use Base64 encoding.");
  808. Err(error::Error {
  809. code: error::ErrorCode::InvalidRequest,
  810. message,
  811. data: None,
  812. })
  813. } else {
  814. Ok(encode_ui_account(
  815. pubkey, account, encoding, None, data_slice,
  816. ))
  817. }
  818. }
  819. fn sanitize_transaction(
  820. transaction: VersionedTransaction,
  821. address_loader: impl AddressLoader,
  822. reserved_account_keys: &HashSet<Pubkey>,
  823. ) -> Result<SanitizedTransaction> {
  824. SanitizedTransaction::try_create(
  825. transaction,
  826. MessageHash::Compute,
  827. None,
  828. address_loader,
  829. reserved_account_keys,
  830. )
  831. .map_err(|err| Error::invalid_params(format!("invalid transaction: {err}")))
  832. }
  833. fn verify_pubkey(input: &str) -> Result<Pubkey> {
  834. input
  835. .parse()
  836. .map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
  837. }