Skip to content

Commit

Permalink
NDEV-2043: Improve performance of neon-api crate (#158)
Browse files Browse the repository at this point in the history
The main purpose of this PR is to remove usages of [`block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html) and to re-use the same code in both an async (`neon-api`) and non-async (`evm-loader`) context.

- Replaced `#[cfg(feature = "tracing")]` with `#[cfg(target_os = "solana")]` and extended its usage to:
  - code from `evm-loader` crate used only as a library (`#[cfg(not(target_os = "solana")]`);
  - code from `evm-loader` crate used only as part of a Solana program (`#[cfg(target_os = "solana")]`).
- Replaced [`axum`](https://github.com/tokio-rs/axum) with [`actix-web`](https://github.com/actix/actix-web), because most of the `evm-loader` crate is based on non-`Send` types and [`actix-web`](https://github.com/actix/actix-web) is a web framework which does not require `Future`s to be `Send`. Inspired from #107.
- Used [`maybe_async`](https://github.com/fMeow/maybe-async-rs) crate to re-write common parts of `evm-loader` crate used both as an async library and as a non-async Solana program. This also removed all usages of [`block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html).
- Simplified all types related to multi-threading in the context of non-`Send` `Future`s: less `Arc`s, less `RwLock`s.
  • Loading branch information
andreisilviudragnea authored and afalaleev committed Oct 11, 2023
1 parent 86fe69e commit fdd81d6
Show file tree
Hide file tree
Showing 57 changed files with 1,401 additions and 1,137 deletions.
452 changes: 302 additions & 150 deletions evm_loader/Cargo.lock

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions evm_loader/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,10 @@ tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-appender = "0.2.2"
axum = "0.6"
tower = { version = "0.4", features = ["make"] }
neon-lib = { path = "../lib" }
tower-request-id = "0.2.1"
http = "0.2.9"
hyper = "0.14.27"
tower-http = { version = "0.4.4", features = ["trace"] }
actix-web = "4.4.0"
actix-request-identifier = "4.1.0"
hex = "0.4.2"
build-info = { version = "0.0.31", features = ["serde"] }

Expand Down
11 changes: 7 additions & 4 deletions evm_loader/api/src/api_server/handlers/build_info.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::build_info::get_build_info;
use axum::{http::StatusCode, Json};
use neon_lib::build_info_common::SlimBuildInfo;
use actix_web::get;
use actix_web::http::StatusCode;
use actix_web::web::Json;
use actix_web::Responder;

#[tracing::instrument(ret)]
pub async fn build_info() -> (StatusCode, Json<SlimBuildInfo>) {
(StatusCode::OK, Json(get_build_info()))
#[get("/build-info")]
pub async fn build_info_route() -> impl Responder {
(Json(get_build_info()), StatusCode::OK)
}
15 changes: 9 additions & 6 deletions evm_loader/api/src/api_server/handlers/emulate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use axum::{http::StatusCode, Json};
use actix_request_identifier::RequestId;
use actix_web::{http::StatusCode, post, web::Json, Responder};
use std::convert::Into;

use crate::api_server::handlers::process_error;
Expand All @@ -9,26 +10,28 @@ use crate::{

use super::{parse_emulation_params, process_result};

#[tracing::instrument(skip(state))]
#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))]
#[post("/emulate")]
pub async fn emulate(
axum::extract::State(state): axum::extract::State<NeonApiState>,
state: NeonApiState,
request_id: RequestId,
Json(emulate_request): Json<EmulateRequestModel>,
) -> (StatusCode, Json<serde_json::Value>) {
) -> impl Responder {
let tx = emulate_request.tx_params.into();

let rpc_client = match api_context::build_rpc_client(&state, emulate_request.slot).await {
Ok(rpc_client) => rpc_client,
Err(e) => return process_error(StatusCode::BAD_REQUEST, &e),
};

let context = Context::new(rpc_client, state.config.clone());
let context = Context::new(&*rpc_client, &state.config);

let (token, chain, steps, accounts, solana_accounts) =
parse_emulation_params(&state.config, &context, &emulate_request.emulation_params).await;

process_result(
&EmulateCommand::execute(
context.rpc_client.as_ref(),
context.rpc_client,
state.config.evm_loader,
tx,
token,
Expand Down
20 changes: 10 additions & 10 deletions evm_loader/api/src/api_server/handlers/get_ether_account_data.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
use crate::api_server::handlers::process_error;
use crate::commands::get_ether_account_data as GetEtherAccountDataCommand;
use crate::{api_context, context::Context, types::request_models::GetEtherRequest, NeonApiState};
use axum::{
extract::{Query, State},
http::StatusCode,
Json,
};
use actix_request_identifier::RequestId;
use actix_web::{get, http::StatusCode, web::Query, Responder};
use std::convert::Into;

use super::process_result;

#[tracing::instrument(skip(state))]
#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))]
#[get("/get-ether-account-data")]
pub async fn get_ether_account_data(
state: NeonApiState,
request_id: RequestId,
Query(req_params): Query<GetEtherRequest>,
State(state): State<NeonApiState>,
) -> (StatusCode, Json<serde_json::Value>) {
) -> impl Responder {
let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await {
Ok(rpc_client) => rpc_client,
Err(e) => return process_error(StatusCode::BAD_REQUEST, &e),
};
let context = Context::new(rpc_client, state.config.clone());

let context = Context::new(&*rpc_client, &state.config);

process_result(
&GetEtherAccountDataCommand::execute(
context.rpc_client.as_ref(),
context.rpc_client,
&state.config.evm_loader,
&req_params.ether,
)
Expand Down
19 changes: 9 additions & 10 deletions evm_loader/api/src/api_server/handlers/get_storage_at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,31 @@ use crate::api_server::handlers::process_error;
use crate::{
api_context, context::Context, types::request_models::GetStorageAtRequest, NeonApiState,
};
use axum::{
extract::{Query, State},
http::StatusCode,
Json,
};
use actix_request_identifier::RequestId;
use actix_web::{get, http::StatusCode, web::Query, Responder};
use std::convert::Into;

use crate::commands::get_storage_at as GetStorageAtCommand;

use super::process_result;

#[tracing::instrument(skip(state))]
#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))]
#[get("/get-storage-at")]
pub async fn get_storage_at(
state: NeonApiState,
request_id: RequestId,
Query(req_params): Query<GetStorageAtRequest>,
State(state): State<NeonApiState>,
) -> (StatusCode, Json<serde_json::Value>) {
) -> impl Responder {
let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await {
Ok(rpc_client) => rpc_client,
Err(e) => return process_error(StatusCode::BAD_REQUEST, &e),
};

let context = Context::new(rpc_client, state.config.clone());
let context = Context::new(&*rpc_client, &state.config);

process_result(
&GetStorageAtCommand::execute(
context.rpc_client.as_ref(),
context.rpc_client,
&state.config.evm_loader,
req_params.contract_id,
&req_params.index,
Expand Down
37 changes: 7 additions & 30 deletions evm_loader/api/src/api_server/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use ethnum::U256;
use actix_web::http::StatusCode;
use actix_web::web::Json;
use evm_loader::types::Address;
use serde::Serialize;
use serde_json::{json, Value};
Expand Down Expand Up @@ -49,30 +47,9 @@ impl From<AddrParseError> for NeonApiError {
}
}

impl IntoResponse for NeonApiError {
fn into_response(self) -> Response {
let (status, error_message) = (StatusCode::INTERNAL_SERVER_ERROR, self.0.to_string());

let body = Json(json!({
"result": "error",
"error":error_message,
}));

(status, body).into_response()
}
}

pub fn u256_of(index: &str) -> Option<U256> {
if index.is_empty() {
return Some(U256::ZERO);
}

U256::from_str_prefixed(index).ok()
}

pub(crate) async fn parse_emulation_params(
config: &Config,
context: &Context,
context: &Context<'_>,
params: &EmulationParamsRequestModel,
) -> (Pubkey, u64, u64, Vec<Address>, Vec<Pubkey>) {
// Read ELF params only if token_mint or chain_id is not set.
Expand Down Expand Up @@ -118,26 +95,26 @@ pub(crate) async fn parse_emulation_params(

fn process_result<T: Serialize>(
result: &NeonApiResult<T>,
) -> (StatusCode, Json<serde_json::Value>) {
) -> (Json<serde_json::Value>, StatusCode) {
match result {
Ok(value) => (
StatusCode::OK,
Json(json!({
"result": "success",
"value": value,
})),
StatusCode::OK,
),
Err(e) => process_error(StatusCode::INTERNAL_SERVER_ERROR, &e.0),
}
}

fn process_error(status_code: StatusCode, e: &NeonError) -> (StatusCode, Json<Value>) {
fn process_error(status_code: StatusCode, e: &NeonError) -> (Json<Value>, StatusCode) {
error!("NeonError: {e}");
(
status_code,
Json(json!({
"result": "error",
"error": e.to_string(),
})),
status_code,
)
}
15 changes: 9 additions & 6 deletions evm_loader/api/src/api_server/handlers/trace.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use axum::{http::StatusCode, Json};
use actix_request_identifier::RequestId;
use actix_web::{http::StatusCode, post, web::Json, Responder};
use std::convert::Into;

use crate::api_server::handlers::process_error;
Expand All @@ -9,11 +10,13 @@ use crate::{

use super::{parse_emulation_params, process_result};

#[tracing::instrument(skip(state))]
#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))]
#[post("/trace")]
pub async fn trace(
axum::extract::State(state): axum::extract::State<NeonApiState>,
state: NeonApiState,
request_id: RequestId,
Json(trace_request): Json<TraceRequestModel>,
) -> (StatusCode, Json<serde_json::Value>) {
) -> impl Responder {
let tx = trace_request.emulate_request.tx_params.into();

let rpc_client =
Expand All @@ -22,7 +25,7 @@ pub async fn trace(
Err(e) => return process_error(StatusCode::BAD_REQUEST, &e),
};

let context = Context::new(rpc_client, state.config.clone());
let context = Context::new(&*rpc_client, &state.config);

let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params(
&state.config,
Expand All @@ -33,7 +36,7 @@ pub async fn trace(

process_result(
&trace_transaction(
context.rpc_client.as_ref(),
context.rpc_client,
state.config.evm_loader,
tx,
token,
Expand Down
1 change: 0 additions & 1 deletion evm_loader/api/src/api_server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
pub mod handlers;
pub mod routes;
pub mod state;
25 changes: 0 additions & 25 deletions evm_loader/api/src/api_server/routes.rs

This file was deleted.

5 changes: 2 additions & 3 deletions evm_loader/api/src/api_server/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ use neon_lib::types::TracerDb;
use solana_client::nonblocking::rpc_client::RpcClient;
use std::sync::Arc;

#[derive(Clone)]
pub struct State {
pub tracer_db: TracerDb,
pub rpc_client: Arc<RpcClient>,
pub config: Arc<Config>,
pub config: Config,
}

impl State {
Expand All @@ -19,7 +18,7 @@ impl State {
config.json_rpc_url.clone(),
config.commitment,
)),
config: Arc::new(config),
config,
}
}
}
Loading

0 comments on commit fdd81d6

Please sign in to comment.