Skip to content

Commit

Permalink
Ndev 3386 caching build config (#581)
Browse files Browse the repository at this point in the history
  • Loading branch information
rnovikov authored Dec 17, 2024
1 parent 02c4bd6 commit ec310b2
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 96 deletions.
8 changes: 4 additions & 4 deletions evm_loader/lib/src/account_storage_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ 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;

const STORAGE_LENGTH: usize = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT;

mod mock_rpc_client {

use crate::commands::get_config::BuildConfigSimulator;
use crate::NeonResult;
use crate::{commands::get_config::ConfigSimulator, rpc::Rpc};
use async_trait::async_trait;
use solana_account_decoder::UiDataSliceConfig;
use solana_client::client_error::Result as ClientResult;
use solana_sdk::account::Account;
use solana_sdk::clock::{Slot, UnixTimestamp};
use solana_sdk::pubkey::Pubkey;
use std::collections::HashMap;

use solana_account_decoder::UiDataSliceConfig;

pub struct MockRpcClient {
accounts: HashMap<Pubkey, Account>,
}
Expand Down Expand Up @@ -91,7 +91,7 @@ mod mock_rpc_client {

#[async_trait(?Send)]
impl BuildConfigSimulator for MockRpcClient {
fn use_cache(&self) -> bool {
fn use_cache_for_chains(&self) -> bool {
false
}
async fn build_config_simulator(&self, _program_id: Pubkey) -> NeonResult<ConfigSimulator> {
Expand Down
105 changes: 62 additions & 43 deletions evm_loader/lib/src/commands/get_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@

use std::collections::BTreeMap;

use crate::rpc::{CallDbClient, CloneRpcClient, Rpc};
use crate::solana_simulator::SolanaSimulator;
use crate::types::programs_cache::KeyAccountCache;
use crate::types::programs_cache::{program_config_cache_add, program_config_cache_get};
use async_trait::async_trait;
use base64::Engine;
use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
pub use solana_account_decoder::UiDataSliceConfig as SliceConfig;
use solana_client::rpc_config::RpcSimulateTransactionConfig;
use solana_sdk::signer::Signer;
use solana_sdk::{instruction::Instruction, pubkey::Pubkey, transaction::Transaction};
use tokio::sync::OnceCell;

use crate::rpc::{CallDbClient, CloneRpcClient};
use crate::solana_simulator::SolanaSimulator;
use crate::NeonResult;

#[derive(Debug, Serialize, Deserialize)]
use tokio::sync::OnceCell;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Status {
Ok,
Emergency,
Expand All @@ -33,7 +35,7 @@ pub struct ChainInfo {
}

#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetConfigResponse {
pub version: String,
pub revision: String,
Expand All @@ -57,17 +59,52 @@ pub enum ConfigSimulator<'r> {

#[async_trait(?Send)]
#[enum_dispatch]
pub trait BuildConfigSimulator {
fn use_cache(&self) -> bool;
pub trait BuildConfigSimulator: Rpc {
fn use_cache_for_chains(&self) -> bool;
async fn get_config(&self, program_id: Pubkey) -> NeonResult<GetConfigResponse> {
let maybe_slot = self.get_last_deployed_slot(&program_id).await?;
if let Some(slot) = maybe_slot {
let key = KeyAccountCache {
addr: program_id,
slot,
};

let rz = program_config_cache_get(&key).await;
if rz.is_some() {
return Ok(rz.unwrap());
};
}
let mut simulator = self.build_config_simulator(program_id).await?;

let (version, revision) = simulator.get_version().await?;

let result = GetConfigResponse {
version,
revision,
status: simulator.get_status().await?,
environment: simulator.get_environment().await?,
chains: simulator.get_chains().await?,
config: simulator.get_properties().await?,
};
if let Some(slot) = maybe_slot {
let key = KeyAccountCache {
addr: program_id,
slot,
};
program_config_cache_add(key, result.clone()).await;
}

Ok(result)
}

async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult<ConfigSimulator>;
}

#[async_trait(?Send)]
impl BuildConfigSimulator for CloneRpcClient {
fn use_cache(&self) -> bool {
fn use_cache_for_chains(&self) -> bool {
true
}

async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult<ConfigSimulator> {
Ok(ConfigSimulator::CloneRpcClient {
program_id,
Expand All @@ -78,13 +115,13 @@ impl BuildConfigSimulator for CloneRpcClient {

#[async_trait(?Send)]
impl BuildConfigSimulator for CallDbClient {
fn use_cache(&self) -> bool {
fn use_cache_for_chains(&self) -> bool {
false
}

async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult<ConfigSimulator> {
let mut simulator = SolanaSimulator::new_without_sync(self).await?;
simulator.sync_accounts(self, &[program_id]).await?;

Ok(ConfigSimulator::ProgramTestContext {
program_id,
simulator,
Expand Down Expand Up @@ -259,49 +296,31 @@ impl ConfigSimulator<'_> {
Ok(result)
}
}

static CHAINS_CACHE: OnceCell<Vec<ChainInfo>> = OnceCell::const_new();
pub async fn execute(
rpc: &impl BuildConfigSimulator,
program_id: Pubkey,
) -> NeonResult<GetConfigResponse> {
let mut simulator = rpc.build_config_simulator(program_id).await?;

let (version, revision) = simulator.get_version().await?;

Ok(GetConfigResponse {
version,
revision,
status: simulator.get_status().await?,
environment: simulator.get_environment().await?,
chains: simulator.get_chains().await?,
config: simulator.get_properties().await?,
})
rpc.get_config(program_id).await
}

static CHAINS_CACHE: OnceCell<Vec<ChainInfo>> = OnceCell::const_new();

pub async fn read_chains(
rpc: &impl BuildConfigSimulator,
program_id: Pubkey,
) -> NeonResult<Vec<ChainInfo>> {
if rpc.use_cache() {
return CHAINS_CACHE
.get_or_try_init(|| get_chains(rpc, program_id))
if rpc.use_cache_for_chains() {
let result = CHAINS_CACHE
.get_or_init(|| async {
rpc.get_config(program_id)
.await
.expect(" get config error for chain info")
.chains
})
.await
.cloned();
.clone();
return Ok(result);
}

get_chains(rpc, program_id).await
}

async fn get_chains(
rpc: &(impl BuildConfigSimulator + Sized),
program_id: Pubkey,
) -> NeonResult<Vec<ChainInfo>> {
rpc.build_config_simulator(program_id)
.await?
.get_chains()
.await
Ok(rpc.get_config(program_id).await?.chains)
}

async fn read_chain_id(
Expand Down
25 changes: 20 additions & 5 deletions evm_loader/lib/src/rpc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
mod db_call_client;
mod emulator_client;
mod validator_client;

pub use db_call_client::CallDbClient;
pub use validator_client::CloneRpcClient;

use crate::commands::get_config::GetConfigResponse;
use crate::commands::get_config::{BuildConfigSimulator, ConfigSimulator};
use crate::{NeonError, NeonResult};
use async_trait::async_trait;
pub use db_call_client::CallDbClient;
use enum_dispatch::enum_dispatch;
use evm_loader::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState;
pub use solana_account_decoder::UiDataSliceConfig as SliceConfig;
use solana_cli::cli::CliError;
use solana_client::client_error::Result as ClientResult;
use solana_client::client_error::{ClientErrorKind, Result as ClientResult};
use solana_sdk::{
account::Account,
clock::{Slot, UnixTimestamp},
message::Message,
native_token::lamports_to_sol,
pubkey::Pubkey,
};
pub use validator_client::CloneRpcClient;

#[async_trait(?Send)]
#[enum_dispatch]
Expand All @@ -28,6 +28,20 @@ pub trait Rpc {
key: &Pubkey,
slice: Option<SliceConfig>,
) -> ClientResult<Option<Account>>;

async fn get_last_deployed_slot(&self, program_id: &Pubkey) -> ClientResult<Option<u64>> {
let slice = SliceConfig {
offset: 0,
length: UpgradeableLoaderState::size_of_programdata_metadata(),
};
let result = self.get_account_slice(program_id, Some(slice)).await;
if let Ok(Some(acc)) = result {
let slot = get_programdata_slot_from_account(&acc)?;
return Ok(slot);
}
Err(ClientErrorKind::Custom("Not account on slot ".to_string()).into())
}

async fn get_account(&self, key: &Pubkey) -> ClientResult<Option<Account>> {
self.get_account_slice(key, None).await
}
Expand Down Expand Up @@ -61,6 +75,7 @@ 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(
Expand Down
Loading

0 comments on commit ec310b2

Please sign in to comment.