From b39f4a2b7e3301c3579ab824e7d9d9b6072a802a Mon Sep 17 00:00:00 2001 From: Novikov Roman Date: Fri, 20 Dec 2024 14:29:50 +0400 Subject: [PATCH 1/4] try to fix --- evm_loader/lib/src/types/programs_cache.rs | 55 +++++++++++++++------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/evm_loader/lib/src/types/programs_cache.rs b/evm_loader/lib/src/types/programs_cache.rs index a72a9fbef..ea1139d40 100644 --- a/evm_loader/lib/src/types/programs_cache.rs +++ b/evm_loader/lib/src/types/programs_cache.rs @@ -26,6 +26,13 @@ pub struct KeyAccountCache { pub addr: Pubkey, pub slot: u64, } +impl KeyAccountCache { + #[must_use] + + pub const fn new(addr: &Pubkey, slot: u64) -> Self { + Self { addr: *addr, slot } + } +} type ProgramDataCache = HashMap; @@ -62,9 +69,26 @@ where type ThreadSaveProgramDataCache = ThreadSaveCache; type ThreadSaveConfigCache = ThreadSaveCache; +type ThreadSaveTestCache = ThreadSaveCache; static ACCOUNT_CACHE_TABLE: OnceCell = OnceCell::const_new(); static CONFIG_CACHE_TABLE: OnceCell = OnceCell::const_new(); +#[allow(dead_code)] +static TEST_CACHE_TABLE: OnceCell = OnceCell::const_new(); +#[allow(dead_code)] +async fn programdata_test_cache_get_instance() -> &'static ThreadSaveTestCache { + TEST_CACHE_TABLE + .get_or_init(|| async { ThreadSaveTestCache::new() }) + .await +} +#[allow(dead_code)] +async fn programdata_test_cache_get(key: &KeyAccountCache) -> Option { + programdata_test_cache_get_instance().await.get(key) +} +#[allow(dead_code)] +async fn programdata_test_cache_add(key: KeyAccountCache, acc: String) { + programdata_test_cache_get_instance().await.add(key, acc); +} pub async fn cut_programdata_from_acc(account: &mut Account, data_slice: SliceConfig) { if data_slice.offset != 0 { @@ -81,13 +105,11 @@ async fn programdata_account_cache_get_instance() -> &'static ThreadSaveProgramD .await } -async fn programdata_account_cache_get(addr: Pubkey, slot: u64) -> Option { - let key = KeyAccountCache { addr, slot }; - programdata_account_cache_get_instance().await.get(&key) +async fn programdata_account_cache_get(key: &KeyAccountCache) -> Option { + programdata_account_cache_get_instance().await.get(key) } -async fn programdata_account_cache_add(addr: Pubkey, slot: u64, acc: Account) { - let key = KeyAccountCache { addr, slot }; +async fn programdata_account_cache_add(key: KeyAccountCache, acc: Account) { programdata_account_cache_get_instance().await.add(key, acc); } @@ -130,16 +152,18 @@ pub async fn programdata_cache_get_values_by_keys( "programdata_keys.size()!=future_requests.size()" ); let results = join_all(future_requests).await; - for (result, key) in results.iter().zip(programdata_keys) { + for (result, addr) in results.iter().zip(programdata_keys) { match result { Ok(Some(account)) => { if let Some(slot_val) = get_programdata_slot_from_account(account)? { - if let Some(acc) = programdata_account_cache_get(*key, slot_val).await { + let key = KeyAccountCache::new(addr, slot_val); + if let Some(acc) = programdata_account_cache_get(&key).await { answer.push(Some(acc)); - } else if let Ok(Some(tmp_acc)) = rpc.get_account(key).await { + } else if let Ok(Some(tmp_acc)) = rpc.get_account(&key.addr).await { let current_slot = get_programdata_slot_from_account(&tmp_acc)?.expect("No current slot "); - programdata_account_cache_add(*key, current_slot, tmp_acc.clone()).await; + let key = KeyAccountCache::new(addr, current_slot); + programdata_account_cache_add(key, tmp_acc.clone()).await; answer.push(Some(tmp_acc)); } else { @@ -150,11 +174,11 @@ pub async fn programdata_cache_get_values_by_keys( } } Ok(None) => { - info!("Account for key {key:?} is None."); + info!("Account for key {addr:?} is None."); answer.push(None); } Err(e) => { - info!("Error fetching account for key {key:?}: {e:?}"); + info!("Error fetching account for key {addr:?}: {e:?}"); } } } @@ -330,9 +354,8 @@ mod tests { .is_none()); } - #[test] - fn test_add_and_get_value() { - let cache: ThreadSaveCache = ThreadSaveCache::new(); + #[tokio::test] + async fn test_add_and_get_value() { let key = KeyAccountCache { slot: 0, addr: Pubkey::new_unique(), @@ -340,10 +363,10 @@ mod tests { let value = "test_value".to_string(); // Add the value to the cache - cache.add(key.clone(), value.clone()); + programdata_test_cache_add(key.clone(), value.clone()).await; // Retrieve the value from the cache - let result = cache.get(&key); + let result = programdata_test_cache_get(&key).await; assert!(result.is_some()); assert_eq!(result.unwrap(), value); } From b53503e6242b9c3fa8c3084eb07656e5379052b9 Mon Sep 17 00:00:00 2001 From: Novikov Roman Date: Mon, 23 Dec 2024 11:43:54 +0400 Subject: [PATCH 2/4] change get_last_depl_slot logic --- evm_loader/lib/src/commands/get_config.rs | 1 + evm_loader/lib/src/rpc/mod.rs | 29 +++++++++++++++++++--- evm_loader/lib/src/types/programs_cache.rs | 27 ++++++++++++++++---- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 35097ba49..cafc776b5 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -63,6 +63,7 @@ pub trait BuildConfigSimulator: Rpc { fn use_cache_for_chains(&self) -> bool; async fn get_config(&self, program_id: Pubkey) -> NeonResult { let maybe_slot = self.get_last_deployed_slot(&program_id).await?; + if let Some(slot) = maybe_slot { let key = KeyAccountCache { addr: program_id, diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index a909a5692..37b5b3c58 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -5,6 +5,9 @@ use crate::commands::get_config::GetConfigResponse; use crate::commands::get_config::{BuildConfigSimulator, ConfigSimulator}; use crate::{NeonError, NeonResult}; use async_trait::async_trait; + +use crate::types::programs_cache::get_program_programdata_address; +use crate::types::programs_cache::get_programdata_slot_from_account; pub use db_call_client::CallDbClient; use enum_dispatch::enum_dispatch; use evm_loader::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState; @@ -30,14 +33,33 @@ pub trait Rpc { ) -> ClientResult>; async fn get_last_deployed_slot(&self, program_id: &Pubkey) -> ClientResult> { + let mut slice_len = std::mem::size_of::(); + if slice_len < UpgradeableLoaderState::size_of_programdata_metadata() { + slice_len = UpgradeableLoaderState::size_of_programdata_metadata(); + } + let slice = SliceConfig { offset: 0, - length: UpgradeableLoaderState::size_of_programdata_metadata(), + length: slice_len, }; + let result = self.get_account_slice(program_id, Some(slice)).await; + // bpfv2 and request account from link + if let Ok(Some(acc)) = result { - let slot = get_programdata_slot_from_account(&acc)?; - return Ok(slot); + let slot = if acc.executable { + get_programdata_slot_from_account(&acc) + .expect("error") + .expect("No slot info") + } else { + let pd_addr = get_program_programdata_address(&acc)?.expect("no program info"); + let rz = self + .get_account_slice(&pd_addr, Some(slice)) + .await? + .expect("No account "); + get_programdata_slot_from_account(&rz)?.expect("No slice ") + }; + return Ok(Some(slot)); } Err(ClientErrorKind::Custom("Not account on slot ".to_string()).into()) } @@ -75,7 +97,6 @@ macro_rules! e { }; } -use crate::types::programs_cache::get_programdata_slot_from_account; pub(crate) use e; pub(crate) async fn check_account_for_fee( diff --git a/evm_loader/lib/src/types/programs_cache.rs b/evm_loader/lib/src/types/programs_cache.rs index ea1139d40..5ec339ff6 100644 --- a/evm_loader/lib/src/types/programs_cache.rs +++ b/evm_loader/lib/src/types/programs_cache.rs @@ -113,15 +113,32 @@ async fn programdata_account_cache_add(key: KeyAccountCache, acc: Account) { programdata_account_cache_get_instance().await.add(key, acc); } -/// in case of Not upgradeable account - return option None -pub fn get_programdata_slot_from_account(acc: &Account) -> ClientResult> { - if !bpf_loader_upgradeable::check_id(&acc.owner) { - return Ok(None); +/// in case of Not upgradeable account - return option None +pub fn get_program_programdata_address(acc: &Account) -> ClientResult> { + assert!(!bpf_loader_upgradeable::check_id(&acc.owner), "NOT AN ACC"); + + match deserialize::(&acc.data) { + Ok(UpgradeableLoaderState::Program { + programdata_address, + .. + }) => Ok(Some(programdata_address)), + Ok(_) => { + panic!("Unexpected account type! Only Program type is acceptable "); + } + Err(e) => { + eprintln!("Error occurred: {e:?}"); + panic!("Failed to deserialize account data."); + } } +} +pub fn get_programdata_slot_from_account(acc: &Account) -> ClientResult> { + assert!(bpf_loader_upgradeable::check_id(&acc.owner), "NOT AN ACC"); match deserialize::(&acc.data) { Ok(UpgradeableLoaderState::ProgramData { slot, .. }) => Ok(Some(slot)), - Ok(_) => Ok(None), + Ok(_) => { + panic!("Unexpected account type! Only ProgramData type is acceptable "); + } Err(e) => { eprintln!("Error occurred: {e:?}"); panic!("Failed to deserialize account data."); From 3ab21f7fbb8e9bc56182d9e647918a1fa47e1b0d Mon Sep 17 00:00:00 2001 From: Novikov Roman Date: Mon, 23 Dec 2024 13:13:27 +0400 Subject: [PATCH 3/4] get slot from program returns 0 --- evm_loader/lib/src/types/programs_cache.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/evm_loader/lib/src/types/programs_cache.rs b/evm_loader/lib/src/types/programs_cache.rs index 5ec339ff6..c9f73b34d 100644 --- a/evm_loader/lib/src/types/programs_cache.rs +++ b/evm_loader/lib/src/types/programs_cache.rs @@ -136,6 +136,14 @@ pub fn get_programdata_slot_from_account(acc: &Account) -> ClientResult(&acc.data) { Ok(UpgradeableLoaderState::ProgramData { slot, .. }) => Ok(Some(slot)), + Ok(UpgradeableLoaderState::Program { + programdata_address, + .. + }) => { + info!(" programdata_address:{programdata_address}"); + Ok(Some(0)) + } + Ok(_) => { panic!("Unexpected account type! Only ProgramData type is acceptable "); } From 56e628081d513c9d01b0d26d15053927bf1693d7 Mon Sep 17 00:00:00 2001 From: Novikov Roman Date: Mon, 23 Dec 2024 16:54:44 +0400 Subject: [PATCH 4/4] program_account --- evm_loader/lib/src/commands/get_config.rs | 11 +++++++++++ evm_loader/lib/src/types/programs_cache.rs | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index cafc776b5..95c4c74f3 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -62,6 +62,16 @@ pub enum ConfigSimulator<'r> { pub trait BuildConfigSimulator: Rpc { fn use_cache_for_chains(&self) -> bool; async fn get_config(&self, program_id: Pubkey) -> NeonResult { + let key_default = KeyAccountCache { + addr: program_id, + slot: 0, + }; + + let maybe_account = program_config_cache_get(&key_default).await; + if let Some(account) = maybe_account { + return Ok(account); + } + let maybe_slot = self.get_last_deployed_slot(&program_id).await?; if let Some(slot) = maybe_slot { @@ -75,6 +85,7 @@ pub trait BuildConfigSimulator: Rpc { return Ok(rz.unwrap()); }; } + let mut simulator = self.build_config_simulator(program_id).await?; let (version, revision) = simulator.get_version().await?; diff --git a/evm_loader/lib/src/types/programs_cache.rs b/evm_loader/lib/src/types/programs_cache.rs index c9f73b34d..15b95c556 100644 --- a/evm_loader/lib/src/types/programs_cache.rs +++ b/evm_loader/lib/src/types/programs_cache.rs @@ -28,7 +28,6 @@ pub struct KeyAccountCache { } impl KeyAccountCache { #[must_use] - pub const fn new(addr: &Pubkey, slot: u64) -> Self { Self { addr: *addr, slot } } @@ -145,7 +144,7 @@ pub fn get_programdata_slot_from_account(acc: &Account) -> ClientResult { - panic!("Unexpected account type! Only ProgramData type is acceptable "); + panic!("Unexpected account type! ProgramData and data type is acceptable "); } Err(e) => { eprintln!("Error occurred: {e:?}");