From f1c29999267477567a4312c3bf8224167b815ac0 Mon Sep 17 00:00:00 2001 From: Novikov Roman Date: Mon, 18 Nov 2024 14:53:33 +0400 Subject: [PATCH] change rpc API --- evm_loader/lib/src/account_storage_tests.rs | 52 +++++++++++-------- evm_loader/lib/src/commands/get_config.rs | 1 - evm_loader/lib/src/rpc/db_call_client.rs | 22 ++++---- evm_loader/lib/src/rpc/emulator_client.rs | 38 ++++++++------ evm_loader/lib/src/rpc/mod.rs | 13 ++--- evm_loader/lib/src/rpc/validator_client.rs | 33 ++---------- evm_loader/lib/src/solana_simulator/mod.rs | 2 +- evm_loader/lib/src/types/mod.rs | 2 +- .../{account_cache.rs => programs_cache.rs} | 47 ++++++++++------- 9 files changed, 103 insertions(+), 107 deletions(-) rename evm_loader/lib/src/types/{account_cache.rs => programs_cache.rs} (87%) diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index 4c746b612..5445f3e15 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -3,6 +3,7 @@ use crate::rpc; use crate::tracing::AccountOverride; use evm_loader::types::vector::VectorVecExt; use hex_literal::hex; +use solana_account_decoder::UiDataSliceConfig; use std::collections::HashMap; use std::str::FromStr; @@ -19,6 +20,8 @@ mod mock_rpc_client { use solana_sdk::pubkey::Pubkey; use std::collections::HashMap; + use solana_account_decoder::UiDataSliceConfig; + pub struct MockRpcClient { accounts: HashMap, } @@ -33,34 +36,33 @@ mod mock_rpc_client { #[async_trait(?Send)] impl Rpc for MockRpcClient { - async fn get_account(&self, key: &Pubkey) -> ClientResult> { - let result = self.accounts.get(key).cloned(); - Ok(result) - } async fn get_account_slice( &self, key: &Pubkey, - offset: usize, - data_size: usize, + slice: Option, ) -> ClientResult> { - if let Some(orig_acc) = self.accounts.get(key) { - let cut_to = usize::min(offset + data_size, orig_acc.data.len()); - let sliced_data = if offset < orig_acc.data.len() { - orig_acc.data[offset..cut_to].to_vec() - } else { - vec![] - }; - - return Ok(Some(Account { - lamports: orig_acc.lamports, - data: sliced_data, - owner: orig_acc.owner, - executable: orig_acc.executable, - rent_epoch: orig_acc.rent_epoch, - })); + if let Some(data_slice) = slice { + if let Some(orig_acc) = self.accounts.get(key) { + let cut_to = + usize::min(data_slice.offset + data_slice.length, orig_acc.data.len()); + let sliced_data = if data_slice.offset < orig_acc.data.len() { + orig_acc.data[data_slice.offset..cut_to].to_vec() + } else { + vec![] + }; + + return Ok(Some(Account { + lamports: orig_acc.lamports, + data: sliced_data, + owner: orig_acc.owner, + executable: orig_acc.executable, + rent_epoch: orig_acc.rent_epoch, + })); + } } - Ok(None) + let result = self.accounts.get(key).cloned(); + Ok(result) } async fn get_multiple_accounts( @@ -1834,8 +1836,12 @@ async fn test_storage_get_account_slice() { .await .expect("Failed to get account slice"); + let slice_cfg = UiDataSliceConfig { + offset: slice_from, + length: slice_size, + }; let sliced_acc = rpc_client - .get_account_slice(&test_key, slice_from, slice_size) + .get_account_slice(&test_key, Some(slice_cfg)) .await .expect("Failed to get account slice"); assert!(acc_no_slice.is_some()); diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 6e0b18318..9fde6a2f6 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -60,7 +60,6 @@ pub enum ConfigSimulator<'r> { pub trait BuildConfigSimulator { fn use_cache(&self) -> bool; async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult; - // get_last_deployed_slot():u64 } #[async_trait(?Send)] diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 04a7500b2..c6da1078c 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,9 +1,10 @@ -use super::{e, Rpc}; +use super::{e, Rpc, SliceConfig}; use crate::types::{TracerDb, TracerDbTrait}; use crate::NeonError; use crate::NeonError::RocksDb; use async_trait::async_trait; use log::debug; +use solana_account_decoder::UiDataSliceConfig; use solana_client::{ client_error::Result as ClientResult, client_error::{ClientError, ClientErrorKind}, @@ -42,9 +43,13 @@ impl CallDbClient { }) } - async fn get_account_at(&self, key: &Pubkey) -> ClientResult> { + async fn get_account_at( + &self, + key: &Pubkey, + slice: Option, + ) -> ClientResult> { self.tracer_db - .get_account_at(key, self.slot, self.tx_index_in_block, None) + .get_account_at(key, self.slot, self.tx_index_in_block, slice) .await .map_err(|e| e!("load account error", key, e)) } @@ -52,24 +57,21 @@ impl CallDbClient { #[async_trait(?Send)] impl Rpc for CallDbClient { - async fn get_account(&self, key: &Pubkey) -> ClientResult> { - self.get_account_at(key).await - } async fn get_account_slice( &self, key: &Pubkey, - _offset: usize, - _data_size: usize, + slice: Option, ) -> ClientResult> { - self.get_account(key).await + self.get_account_at(key, slice).await } + async fn get_multiple_accounts( &self, pubkeys: &[Pubkey], ) -> ClientResult>> { let mut result = Vec::new(); for key in pubkeys { - result.push(self.get_account_at(key).await?); + result.push(self.get_account_at(key, None).await?); } debug!("get_multiple_accounts: pubkeys={pubkeys:?} result={result:?}"); Ok(result) diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs index 6d00e96eb..ae35c25ac 100644 --- a/evm_loader/lib/src/rpc/emulator_client.rs +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -10,29 +10,35 @@ use solana_sdk::{ use crate::account_storage::{fake_operator, EmulatorAccountStorage}; -use super::Rpc; +use super::{Rpc, SliceConfig}; #[async_trait(?Send)] impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { - async fn get_account(&self, key: &Pubkey) -> ClientResult> { - if *key == self.operator() { - return Ok(Some(fake_operator())); - } - - if let Some(account_data) = self.accounts_get(key) { - return Ok(Some(Account::from(&*account_data))); - } - - let account = self._get_account_from_rpc(*key).await?.cloned(); - Ok(account) - } async fn get_account_slice( &self, key: &Pubkey, - _offset: usize, - _data_size: usize, + slice: Option, ) -> ClientResult> { - self.get_account(key).await + let answer_account = if *key == self.operator() { + Some(fake_operator()) + } else if let Some(account_data) = self.accounts_get(key) { + Some(Account::from(&*account_data)) + } else { + self._get_account_from_rpc(*key).await?.cloned() + }; + + if let Some(data_slice) = slice { + // if only slice is necessary - cut data + if let Some(mut account) = answer_account { + if data_slice.offset != 0 { + account.data.drain(0..data_slice.offset); + } + account.data.truncate(data_slice.length); + return Ok(Some(account)); + } + } + + Ok(answer_account) } async fn get_multiple_accounts( diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 96c8de0e5..d14e1763c 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -9,27 +9,28 @@ use crate::commands::get_config::{BuildConfigSimulator, ConfigSimulator}; use crate::{NeonError, NeonResult}; use async_trait::async_trait; use enum_dispatch::enum_dispatch; +pub use solana_account_decoder::UiDataSliceConfig as SliceConfig; use solana_cli::cli::CliError; use solana_client::client_error::Result as ClientResult; -use solana_sdk::message::Message; -use solana_sdk::native_token::lamports_to_sol; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, + message::Message, + native_token::lamports_to_sol, pubkey::Pubkey, }; #[async_trait(?Send)] #[enum_dispatch] pub trait Rpc { - async fn get_account(&self, key: &Pubkey) -> ClientResult>; - async fn get_account_slice( &self, key: &Pubkey, - offset: usize, - data_size: usize, + slice: Option, ) -> ClientResult>; + async fn get_account(&self, key: &Pubkey) -> ClientResult> { + self.get_account_slice(key, None).await + } async fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult>>; diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 2bb6bf905..e8a0585c9 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -1,8 +1,8 @@ use crate::{config::APIOptions, Config}; -use super::Rpc; +use super::{Rpc, SliceConfig}; use async_trait::async_trait; -use solana_account_decoder::{UiAccount, UiAccountEncoding, UiDataSliceConfig}; +use solana_account_decoder::{UiAccount, UiAccountEncoding}; use solana_client::{ client_error::{ClientError, ClientErrorKind, Result as ClientResult}, nonblocking::rpc_client::RpcClient, @@ -114,41 +114,16 @@ impl Deref for CloneRpcClient { #[async_trait(?Send)] impl Rpc for CloneRpcClient { - async fn get_account(&self, key: &Pubkey) -> ClientResult> { - let request = || { - let config = RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Base64Zstd), - commitment: Some(self.commitment()), - data_slice: None, - min_context_slot: None, - }; - let params = serde_json::json!([key.to_string(), config]); - - self.send(RpcRequest::GetAccountInfo, params) - }; - - let response: serde_json::Value = with_retries(self.max_retries, request).await?; - let response: Response> = serde_json::from_value(response)?; - - let account = response.value.and_then(|v| v.decode()); - Ok(account) - } async fn get_account_slice( &self, key: &Pubkey, - offset: usize, - data_size: usize, + slice: Option, ) -> ClientResult> { - let slice_shape = UiDataSliceConfig { - offset, - length: data_size, - }; - let request = || { let config = RpcAccountInfoConfig { encoding: Some(UiAccountEncoding::Base64Zstd), commitment: Some(self.commitment()), - data_slice: Some(slice_shape), + data_slice: slice, min_context_slot: None, }; let params = serde_json::json!([key.to_string(), config]); diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 2ff9d7522..942f5a309 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -52,7 +52,7 @@ use solana_sdk::{ pub use utils::SyncState; use crate::rpc::Rpc; -use crate::types::account_cache::acc_hash_get_values_by_keys; +use crate::types::programs_cache::acc_hash_get_values_by_keys; mod error; mod utils; diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index acd5889f7..8678571af 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,6 +1,6 @@ pub mod tracer_ch_common; -pub mod account_cache; +pub mod programs_cache; pub(crate) mod tracer_ch_db; pub mod tracer_rocks_db; diff --git a/evm_loader/lib/src/types/account_cache.rs b/evm_loader/lib/src/types/programs_cache.rs similarity index 87% rename from evm_loader/lib/src/types/account_cache.rs rename to evm_loader/lib/src/types/programs_cache.rs index 6b2318894..8d00cde0d 100644 --- a/evm_loader/lib/src/types/account_cache.rs +++ b/evm_loader/lib/src/types/programs_cache.rs @@ -26,12 +26,13 @@ pub struct KeyAccountCache { slot: u64, } -type AccCache = HashMap; -type ProtectedAppCache = RwLock; +pub use solana_account_decoder::UiDataSliceConfig as SliceConfig; +type ProgramDataCache = HashMap; +type ThreadSaveProgramDataCache = RwLock; -static LOCAL_CONFIG: OnceCell = OnceCell::const_new(); +static LOCAL_CONFIG: OnceCell = OnceCell::const_new(); -async fn acc_hash_get_instance() -> &'static ProtectedAppCache { +async fn acc_hash_get_instance() -> &'static ThreadSaveProgramDataCache { LOCAL_CONFIG .get_or_init(|| async { let map = HashMap::new(); @@ -84,8 +85,10 @@ pub async fn acc_hash_get_values_by_keys( for key in programdata_keys { future_requests.push(rpc.get_account_slice( key, - 0, - UpgradeableLoaderState::size_of_programdata_metadata(), + Some(SliceConfig { + offset: 0, + length: UpgradeableLoaderState::size_of_programdata_metadata(), + }), )); //future_requests.push(rpc.get_account_slice(key, 0, 512)); } @@ -164,26 +167,22 @@ impl FakeRpc { #[async_trait(?Send)] impl Rpc for FakeRpc { - async fn get_account(&self, pubkey: &Pubkey) -> ClientResult> { - assert!(self.accounts.contains_key(pubkey), " "); - Ok(Some(self.accounts.get(pubkey).unwrap().clone())) - } - async fn get_account_slice( &self, pubkey: &Pubkey, - offset: usize, - data_size: usize, + slice: Option, ) -> ClientResult> { assert!(self.accounts.contains_key(pubkey), " "); - let mut answer = self.accounts.get(pubkey).unwrap().clone(); - if offset != 0 { - answer - .data - .drain(..std::cmp::min(answer.data.len(), offset)); + let mut answer = self.accounts.get(pubkey).unwrap().clone(); + if let Some(data_slice) = slice { + if data_slice.offset != 0 { + answer + .data + .drain(..std::cmp::min(answer.data.len(), data_slice.offset)); + } + answer.data.truncate(data_slice.length); } - answer.data.truncate(data_size); Ok(Some(answer)) } @@ -235,7 +234,15 @@ mod tests { panic!("fake rpc returned error"); } - let test3_acc = rpc.get_account_slice(&test_key, 0, 1024).await; + let test3_acc = rpc + .get_account_slice( + &test_key, + Some(SliceConfig { + offset: 0, + length: 1024, + }), + ) + .await; assert_eq!(1024, test3_acc.unwrap().expect("test fail").data.len()); } #[tokio::test]