diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7600e18b0..8ad657fb7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -12,6 +12,196 @@ dependencies = [ "regex", ] +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash 0.8.3", + "base64 0.21.4", + "bitflags 2.4.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand 0.8.5", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd 0.12.4", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote 1.0.32", + "syn 2.0.28", +] + +[[package]] +name = "actix-request-identifier" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f620de7c806297b88cf39da5ef4293a59f7dc219a9838433e83238e53a9c7057" +dependencies = [ + "actix-web", + "futures", + "uuid", +] + +[[package]] +name = "actix-router" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2 0.5.4", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash 0.8.3", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.5.4", + "time 0.3.20", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +dependencies = [ + "actix-router", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "adler" version = "1.0.2" @@ -347,9 +537,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -373,55 +563,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "axum" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "base64" version = "0.12.3" @@ -754,6 +895,15 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "bytestring" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +dependencies = [ + "bytes", +] + [[package]] name = "camino" version = "1.1.6" @@ -1031,6 +1181,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time 0.3.20", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1553,6 +1714,7 @@ name = "evm-loader" version = "1.5.0-dev" dependencies = [ "arrayref", + "async-trait", "bincode", "borsh 0.9.3", "cfg-if", @@ -1562,6 +1724,7 @@ dependencies = [ "hex", "linked_list_allocator", "log", + "maybe-async", "mpl-token-metadata", "ripemd", "rlp", @@ -2001,12 +2164,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - [[package]] name = "httparse" version = "1.8.0" @@ -2042,7 +2199,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2248,6 +2405,12 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + [[package]] name = "lazy_static" version = "1.4.0" @@ -2353,6 +2516,23 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" +[[package]] +name = "local-channel" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + [[package]] name = "lock_api" version = "0.4.9" @@ -2413,10 +2593,15 @@ dependencies = [ ] [[package]] -name = "matchit" -version = "0.7.0" +name = "maybe-async" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] [[package]] name = "memchr" @@ -2597,15 +2782,14 @@ dependencies = [ name = "neon-api" version = "0.1.0" dependencies = [ - "axum", + "actix-request-identifier", + "actix-web", "build-info", "build-info-build", "clap 2.34.0", "ethnum", "evm-loader", "hex", - "http", - "hyper", "neon-lib", "serde", "serde_json", @@ -2613,8 +2797,6 @@ dependencies = [ "solana-sdk", "tokio", "tower", - "tower-http", - "tower-request-id", "tracing", "tracing-appender", "tracing-subscriber", @@ -2648,7 +2830,6 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "axum", "bincode", "bs58", "build-info", @@ -2658,7 +2839,6 @@ dependencies = [ "evm-loader", "goblin 0.6.1", "hex", - "lazy_static", "log", "rand 0.8.5", "scroll", @@ -3027,26 +3207,6 @@ dependencies = [ "num", ] -[[package]] -name = "pin-project" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" -dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", -] - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -3237,7 +3397,7 @@ checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ "libc", "quinn-proto", - "socket2", + "socket2 0.4.9", "tracing", "windows-sys 0.42.0", ] @@ -3847,15 +4007,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3914,6 +4065,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.9.9" @@ -4059,6 +4221,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "solana-account-decoder" version = "1.16.14" @@ -4080,7 +4252,7 @@ dependencies = [ "spl-token", "spl-token-2022", "thiserror", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -4421,7 +4593,7 @@ dependencies = [ "rand 0.7.3", "serde", "serde_derive", - "socket2", + "socket2 0.4.9", "solana-logger", "solana-sdk", "solana-version", @@ -5080,12 +5252,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "synstructure" version = "0.12.6" @@ -5257,7 +5423,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", "windows-sys 0.45.0", ] @@ -5377,9 +5543,7 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "futures-core", "futures-util", - "pin-project", "pin-project-lite", "tokio", "tower-layer", @@ -5387,43 +5551,12 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.4.0", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower-layer" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" -[[package]] -name = "tower-request-id" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4fbab3421649e92056980671a04d83aa76e3bd4e7b755a9d9ae24eb2015b25" -dependencies = [ - "http", - "tower-layer", - "tower-service", - "ulid", -] - [[package]] name = "tower-service" version = "0.3.2" @@ -5538,15 +5671,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "ulid" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9d3475df4ff8a8f7804c0fc3394b44fdcfc4fb635717bf05fbb7c41c83a376" -dependencies = [ - "rand 0.8.5", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -5650,6 +5774,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom 0.2.9", +] + [[package]] name = "valuable" version = "0.1.0" @@ -6083,7 +6216,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe 6.0.6", ] [[package]] @@ -6096,6 +6238,16 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 9c601bfbd..3f7ddc40c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -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"] } diff --git a/evm_loader/api/src/api_server/handlers/build_info.rs b/evm_loader/api/src/api_server/handlers/build_info.rs index a46c6ceed..e57d05a4a 100644 --- a/evm_loader/api/src/api_server/handlers/build_info.rs +++ b/evm_loader/api/src/api_server/handlers/build_info.rs @@ -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) { - (StatusCode::OK, Json(get_build_info())) +#[get("/build-info")] +pub async fn build_info_route() -> impl Responder { + (Json(get_build_info()), StatusCode::OK) } diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 6403c940f..1a3da87a7 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -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; @@ -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("/emulate")] pub async fn emulate( - axum::extract::State(state): axum::extract::State, + state: NeonApiState, + request_id: RequestId, Json(emulate_request): Json, -) -> (StatusCode, Json) { +) -> impl Responder { let tx = emulate_request.tx_params.into(); let rpc_client = match api_context::build_rpc_client(&state, emulate_request.slot).await { @@ -21,14 +24,14 @@ pub async fn emulate( 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, diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index b16854bc7..e0e77e50d 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -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, - State(state): State, -) -> (StatusCode, Json) { +) -> 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, ) diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index f32ebd5d0..c19d0046a 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -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, - State(state): State, -) -> (StatusCode, Json) { +) -> 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, diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 252a5fb89..65b631bde 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -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}; @@ -49,30 +47,9 @@ impl From 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 { - 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
, Vec) { // Read ELF params only if token_mint or chain_id is not set. @@ -118,26 +95,26 @@ pub(crate) async fn parse_emulation_params( fn process_result( result: &NeonApiResult, -) -> (StatusCode, Json) { +) -> (Json, 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) { +fn process_error(status_code: StatusCode, e: &NeonError) -> (Json, StatusCode) { error!("NeonError: {e}"); ( - status_code, Json(json!({ "result": "error", "error": e.to_string(), })), + status_code, ) } diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index 43cbf8403..d53d552de 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -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; @@ -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, + state: NeonApiState, + request_id: RequestId, Json(trace_request): Json, -) -> (StatusCode, Json) { +) -> impl Responder { let tx = trace_request.emulate_request.tx_params.into(); let rpc_client = @@ -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, @@ -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, diff --git a/evm_loader/api/src/api_server/mod.rs b/evm_loader/api/src/api_server/mod.rs index 9b94b34ed..53b4478d2 100644 --- a/evm_loader/api/src/api_server/mod.rs +++ b/evm_loader/api/src/api_server/mod.rs @@ -1,3 +1,2 @@ pub mod handlers; -pub mod routes; pub mod state; diff --git a/evm_loader/api/src/api_server/routes.rs b/evm_loader/api/src/api_server/routes.rs deleted file mode 100644 index 1b9a31457..000000000 --- a/evm_loader/api/src/api_server/routes.rs +++ /dev/null @@ -1,25 +0,0 @@ -use axum::{ - routing::{get, post}, - Router, -}; -use tower::ServiceBuilder; - -// use evm_loader::types::Address; -use crate::{ - api_server::handlers::{ - build_info::build_info, emulate::emulate, get_ether_account_data::get_ether_account_data, - get_storage_at::get_storage_at, trace::trace, - }, - NeonApiState, -}; - -pub fn register() -> Router { - ServiceBuilder::new().service::>( - Router::new() - .route("/emulate", post(emulate)) // Obsolete - .route("/get-storage-at", get(get_storage_at)) - .route("/get-ether-account-data", get(get_ether_account_data)) - .route("/trace", post(trace)) - .route("/build-info", get(build_info)), - ) -} diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index 1b49fe103..1205a9b00 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -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, - pub config: Arc, + pub config: Config, } impl State { @@ -19,7 +18,7 @@ impl State { config.json_rpc_url.clone(), config.commitment, )), - config: Arc::new(config), + config, } } } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index d9091abc8..fd0fad5a4 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] #![deny(warnings)] #![deny(clippy::all, clippy::pedantic)] mod api_context; @@ -7,35 +6,35 @@ mod api_server; #[allow(clippy::module_name_repetitions)] mod build_info; +use actix_web::web; +use actix_web::App; +use actix_web::HttpServer; use api_server::handlers::NeonApiError; -use axum::Router; -pub use neon_lib::account_storage; pub use neon_lib::commands; pub use neon_lib::config; pub use neon_lib::context; pub use neon_lib::errors; -pub use neon_lib::rpc; -pub use neon_lib::syscall_stubs; pub use neon_lib::types; use tracing_appender::non_blocking::NonBlockingBuilder; -use std::sync::Arc; +use actix_request_identifier::RequestIdentifier; +use actix_web::web::Data; use std::{env, net::SocketAddr, str::FromStr}; +use crate::api_server::handlers::build_info::build_info_route; +use crate::api_server::handlers::emulate::emulate; +use crate::api_server::handlers::get_ether_account_data::get_ether_account_data; +use crate::api_server::handlers::get_storage_at::get_storage_at; +use crate::api_server::handlers::trace::trace; use crate::build_info::get_build_info; pub use config::Config; pub use context::Context; -use http::Request; -use hyper::Body; -use tokio::signal::{self}; -use tower_http::trace::TraceLayer; -use tower_request_id::{RequestId, RequestIdLayer}; -use tracing::{info, info_span}; +use tracing::info; type NeonApiResult = Result; -type NeonApiState = Arc; +type NeonApiState = Data; -#[tokio::main(flavor = "multi_thread", worker_threads = 512)] +#[actix_web::main] async fn main() -> NeonApiResult<()> { let options = api_options::parse(); @@ -44,10 +43,7 @@ async fn main() -> NeonApiResult<()> { .lossy(false) .finish(std::io::stdout()); - tracing_subscriber::fmt() - .with_thread_ids(true) - .with_writer(non_blocking) - .init(); + tracing_subscriber::fmt().with_writer(non_blocking).init(); info!("{}", get_build_info()); @@ -55,29 +51,7 @@ async fn main() -> NeonApiResult<()> { let config = config::create_from_api_config(&api_config)?; - let state: NeonApiState = Arc::new(api_server::state::State::new(config)); - - let app = Router::new() - .nest("/api", api_server::routes::register()) - .with_state(state) - .layer( - // Let's create a tracing span for each request - TraceLayer::new_for_http().make_span_with(|request: &Request| { - // We get the request id from the extensions - let request_id = request - .extensions() - .get::() - .map_or_else(|| "unknown".into(), ToString::to_string); - // And then we put it along with other information into the `request` span - info_span!( - "request", - id = %request_id, - ) - }), - ) - // This layer creates a new id for each request and puts it into the request extensions. - // Note that it should be added after the Trace layer. - .layer(RequestIdLayer); + let state: NeonApiState = Data::new(api_server::state::State::new(config)); let listener_addr = options .value_of("host") @@ -89,37 +63,23 @@ async fn main() -> NeonApiResult<()> { let addr = SocketAddr::from_str(listener_addr.as_str())?; tracing::info!("listening on {}", addr); - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .with_graceful_shutdown(shutdown_signal()) - .await - .unwrap(); + HttpServer::new(move || { + App::new().service( + web::scope("/api") + .app_data(state.clone()) + .service(build_info_route) + .service(emulate) + .service(get_ether_account_data) + .service(get_storage_at) + .service(trace) + .wrap(RequestIdentifier::with_uuid()), + ) + }) + .bind(addr) + .unwrap() + .run() + .await + .unwrap(); Ok(()) } - -async fn shutdown_signal() { - let ctrl_c = async { - signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - }; - - #[cfg(unix)] - let terminate = async { - signal::unix::signal(signal::unix::SignalKind::terminate()) - .expect("failed to install signal handler") - .recv() - .await; - }; - - #[cfg(not(unix))] - let terminate = std::future::pending::<()>(); - - tokio::select! { - _ = ctrl_c => {}, - _ = terminate => {}, - } - - println!("signal received, starting graceful shutdown"); -} diff --git a/evm_loader/cli/src/config.rs b/evm_loader/cli/src/config.rs index 6d3382ce9..5ed698eb0 100644 --- a/evm_loader/cli/src/config.rs +++ b/evm_loader/cli/src/config.rs @@ -6,7 +6,7 @@ use solana_clap_utils::{ keypair::keypair_from_path, }; use solana_sdk::commitment_config::CommitmentConfig; -use std::{str::FromStr, sync::Arc}; +use std::str::FromStr; /// # Panics /// # Errors @@ -43,8 +43,7 @@ pub fn create(options: &ArgMatches) -> Result { "fee_payer", true, ) - .ok() - .map(Arc::new); + .ok(); let db_config = options .value_of("db_config") diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 2b7d4ee5c..615ce4419 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -13,7 +13,7 @@ use neon_lib::{ get_ether_account_data, get_neon_elf, get_neon_elf::CachedElfParams, get_storage_at, init_environment, trace, }, - errors, + errors, rpc, types::{self, AccessListItem}, Context, }; @@ -30,15 +30,18 @@ use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::pubkey::Pubkey; use std::str::FromStr; -use std::sync::Arc; use tokio::time::Instant; +pub use neon_lib::context::*; +use neon_lib::rpc::CallDbClient; + use crate::build_info::get_build_info; use crate::{ errors::NeonError, types::{TransactionParams, TxParams}, }; use evm_loader::types::Address; +use neon_lib::types::TracerDb; type NeonCliResult = Result; @@ -46,9 +49,27 @@ async fn run<'a>(options: &'a ArgMatches<'a>) -> NeonCliResult { let slot: Option = options .value_of("slot") .map(|slot_str| slot_str.parse().expect("slot parse error")); + + let config = config::create(options)?; + let (cmd, params) = options.subcommand(); - let config = Arc::new(config::create(options)?); - let context = Context::new_from_config(config.clone(), slot).await?; + + let rpc_client: Box = if let Some(slot) = slot { + Box::new( + CallDbClient::new( + TracerDb::new(config.db_config.as_ref().expect("db-config not found")), + slot, + ) + .await?, + ) + } else { + Box::new(RpcClient::new_with_commitment( + config.json_rpc_url.clone(), + config.commitment, + )) + }; + + let context = Context::new(&*rpc_client, &config); execute(cmd, params, &config, &context).await } @@ -75,7 +96,7 @@ fn print_result(result: &NeonCliResult) { println!("{}", serde_json::to_string_pretty(&result).unwrap()); } -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() { let time_start = Instant::now(); @@ -104,7 +125,7 @@ async fn execute<'a>( cmd: &str, params: Option<&'a ArgMatches<'a>>, config: &'a Config, - context: &'a Context, + context: &'a Context<'_>, ) -> NeonCliResult { match (cmd, params) { ("emulate", Some(params)) => { @@ -112,7 +133,7 @@ async fn execute<'a>( let (token, chain, steps, accounts, solana_accounts) = parse_tx_params(config, context, params).await; emulate::execute( - context.rpc_client.as_ref(), + context.rpc_client, config.evm_loader, tx, token, @@ -132,7 +153,7 @@ async fn execute<'a>( let (token, chain, steps, accounts, solana_accounts) = parse_tx_params(config, context, params).await; trace::trace_transaction( - context.rpc_client.as_ref(), + context.rpc_client, config.evm_loader, tx, token, @@ -182,7 +203,7 @@ async fn execute<'a>( } ("get-ether-account-data", Some(params)) => { let ether = address_of(params, "ether").expect("ether parse error"); - get_ether_account_data::execute(context.rpc_client.as_ref(), &config.evm_loader, ðer) + get_ether_account_data::execute(context.rpc_client, &config.evm_loader, ðer) .await .map(|result| json!(result)) } @@ -190,7 +211,7 @@ async fn execute<'a>( let storage_account = pubkey_of(params, "storage_account").expect("storage_account parse error"); cancel_trx::execute( - context.rpc_client.as_ref(), + context.rpc_client, context.signer()?.as_ref(), config.evm_loader, &storage_account, @@ -219,14 +240,9 @@ async fn execute<'a>( ("get-storage-at", Some(params)) => { let contract_id = address_of(params, "contract_id").expect("contract_it parse error"); let index = u256_of(params, "index").expect("index parse error"); - get_storage_at::execute( - context.rpc_client.as_ref(), - &config.evm_loader, - contract_id, - &index, - ) - .await - .map(|hash| json!(hex::encode(hash.0))) + get_storage_at::execute(context.rpc_client, &config.evm_loader, contract_id, &index) + .await + .map(|hash| json!(hex::encode(hash.0))) } _ => unreachable!(), } @@ -268,7 +284,7 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { pub async fn parse_tx_params<'a>( config: &Config, - context: &Context, + context: &Context<'_>, params: &'a ArgMatches<'a>, ) -> (Pubkey, u64, u64, Vec
, Vec) { // Read ELF params only if token_mint or chain_id is not set. diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index bc9cc62d2..c193af9cf 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" -evm-loader = { path = "../program", default-features = false, features = ["log", "tracing"] } +evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } solana-sdk = "=1.16.14" solana-client = "=1.16.14" solana-clap-utils = "=1.16.14" @@ -28,11 +28,9 @@ ethnum = { version = "1.4", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } -lazy_static = "1.4" clickhouse = "0.11.5" tracing = "0.1" -async-trait = "0.1.68" -axum = "0.6" +async-trait = "0.1.73" build-info = "0.0.31" [build-dependencies] diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 8dcb3980a..9467cd9b9 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,5 +1,5 @@ +use async_trait::async_trait; use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; -use tokio::sync::RwLock; use crate::{rpc::Rpc, NeonError}; use ethnum::U256; @@ -31,7 +31,7 @@ use solana_sdk::{ sysvar::{slot_hashes, Sysvar}, }; -use crate::types::{block, PubkeyBase58}; +use crate::types::PubkeyBase58; const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); @@ -109,8 +109,8 @@ pub struct SolanaAccount { #[allow(clippy::module_name_repetitions)] pub struct EmulatorAccountStorage<'a> { - pub accounts: RwLock>, - pub solana_accounts: RwLock>, + pub accounts: RefCell>, + pub solana_accounts: RefCell>, rpc_client: &'a dyn Rpc, evm_loader: Pubkey, block_number: u64, @@ -150,8 +150,8 @@ impl<'a> EmulatorAccountStorage<'a> { }; Ok(Self { - accounts: RwLock::new(HashMap::new()), - solana_accounts: RwLock::new(HashMap::new()), + accounts: RefCell::new(HashMap::new()), + solana_accounts: RefCell::new(HashMap::new()), rpc_client, evm_loader, block_number, @@ -208,16 +208,15 @@ impl<'a> EmulatorAccountStorage<'a> { .iter() .zip(accounts.iter().take(addresses.len())) .zip(pubkeys.iter().take(addresses.len())); - let mut accounts_storage = self.accounts.write().await; for ((&address, account), &pubkey) in entries { - accounts_storage.insert( + self.accounts.borrow_mut().insert( address, NeonAccount::new(address, pubkey, account.clone(), false), ); } let entries = accounts.iter().skip(addresses.len()).zip(solana_accounts); - let mut solana_accounts_storage = self.solana_accounts.write().await; + let mut solana_accounts_storage = self.solana_accounts.borrow_mut(); for (account, &pubkey) in entries { solana_accounts_storage.insert( pubkey, @@ -232,9 +231,7 @@ impl<'a> EmulatorAccountStorage<'a> { } pub async fn get_account(&self, pubkey: &Pubkey) -> client_error::Result> { - let mut accounts = self.solana_accounts.write().await; - - if let Some(account) = accounts.get(pubkey) { + if let Some(account) = self.solana_accounts.borrow().get(pubkey) { if let Some(ref data) = account.data { return Ok(Some(data.clone())); } @@ -245,7 +242,8 @@ impl<'a> EmulatorAccountStorage<'a> { .get_account_with_commitment(pubkey, self.commitment) .await?; - accounts + self.solana_accounts + .borrow_mut() .entry(*pubkey) .and_modify(|a| a.data = result.value.clone()) .or_insert(SolanaAccount { @@ -279,19 +277,17 @@ impl<'a> EmulatorAccountStorage<'a> { } async fn add_ethereum_account(&self, address: &Address, writable: bool) -> bool { - let mut accounts = self.accounts.write().await; - - if let Some(ref mut account) = accounts.get_mut(address) { + if let Some(ref mut account) = self.accounts.borrow_mut().get_mut(address) { account.writable |= writable; - true - } else { - let account = - NeonAccount::rpc_load(self.rpc_client, &self.evm_loader, *address, writable).await; - accounts.insert(*address, account); - - false + return true; } + + let account = + NeonAccount::rpc_load(self.rpc_client, &self.evm_loader, *address, writable).await; + self.accounts.borrow_mut().insert(*address, account); + + false } async fn add_solana_account(&self, pubkey: Pubkey, is_writable: bool) { @@ -303,7 +299,7 @@ impl<'a> EmulatorAccountStorage<'a> { return; } - let mut solana_accounts = self.solana_accounts.write().await; + let mut solana_accounts = self.solana_accounts.borrow_mut(); let account = SolanaAccount { pubkey: pubkey.into(), @@ -361,7 +357,7 @@ impl<'a> EmulatorAccountStorage<'a> { self.add_solana_account(*storage_account.pubkey(), true) .await; - if self.storage(address, index) == [0_u8; 32] { + if self.storage(address, index).await == [0_u8; 32] { let metadata_size = EthereumStorage::SIZE; let element_size = 1 + std::mem::size_of_val(value); @@ -414,7 +410,7 @@ impl<'a> EmulatorAccountStorage<'a> { let mut iterations = 0_usize; - let mut accounts = self.accounts.write().await; + let mut accounts = self.accounts.borrow_mut(); for (address, operation) in operations { let new_size = match operation { AccountOperation::Create { space } => space, @@ -443,7 +439,7 @@ impl<'a> EmulatorAccountStorage<'a> { { self.add_ethereum_account(address, false).await; - let mut accounts = self.accounts.write().await; + let mut accounts = self.accounts.borrow_mut(); let solana_account = accounts.get_mut(address).expect("get account error"); if let Some(account_data) = &mut solana_account.data { @@ -469,7 +465,7 @@ impl<'a> EmulatorAccountStorage<'a> { { self.add_ethereum_account(address, false).await; - let mut accounts = self.accounts.write().await; + let mut accounts = self.accounts.borrow_mut(); let solana_account = accounts.get_mut(address).expect("get account error"); if let Some(account_data) = &mut solana_account.data { @@ -485,6 +481,7 @@ impl<'a> EmulatorAccountStorage<'a> { } } +#[async_trait(?Send)] impl<'a> AccountStorage for EmulatorAccountStorage<'a> { fn neon_token_mint(&self) -> &Pubkey { info!("neon_token_mint"); @@ -511,12 +508,12 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { self.block_timestamp.try_into().unwrap() } - fn block_hash(&self, slot: u64) -> [u8; 32] { + async fn block_hash(&self, slot: u64) -> [u8; 32] { info!("block_hash {slot}"); - block(self.add_solana_account(slot_hashes::ID, false)); + self.add_solana_account(slot_hashes::ID, false).await; - if let Ok(Some(slot_hashes_account)) = block(self.get_account(&slot_hashes::ID)) { + if let Ok(Some(slot_hashes_account)) = self.get_account(&slot_hashes::ID).await { let slot_hashes_data = slot_hashes_account.data.as_slice(); find_slot_hash(slot, slot_hashes_data) } else { @@ -524,82 +521,87 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } } - fn exists(&self, address: &Address) -> bool { + async fn exists(&self, address: &Address) -> bool { info!("exists {address}"); - block(self.add_ethereum_account(address, false)); + self.add_ethereum_account(address, false).await; - let accounts = block(self.accounts.read()); + let accounts = self.accounts.borrow(); accounts.contains_key(address) } - fn nonce(&self, address: &Address) -> u64 { + async fn nonce(&self, address: &Address) -> u64 { info!("nonce {address}"); - block(self.ethereum_account_map_or(address, 0_u64, |a| a.trx_count)) + self.ethereum_account_map_or(address, 0_u64, |a| a.trx_count) + .await } - fn balance(&self, address: &Address) -> U256 { + async fn balance(&self, address: &Address) -> U256 { info!("balance {address}"); - block(self.ethereum_account_map_or(address, U256::ZERO, |a| a.balance)) + self.ethereum_account_map_or(address, U256::ZERO, |a| a.balance) + .await } - fn code_size(&self, address: &Address) -> usize { + async fn code_size(&self, address: &Address) -> usize { info!("code_size {address}"); - block(self.ethereum_account_map_or(address, 0, |a| a.code_size as usize)) + self.ethereum_account_map_or(address, 0, |a| a.code_size as usize) + .await } - fn code_hash(&self, address: &Address) -> [u8; 32] { + async fn code_hash(&self, address: &Address) -> [u8; 32] { use solana_sdk::keccak::hash; info!("code_hash {address}"); // https://eips.ethereum.org/EIPS/eip-1052 // https://eips.ethereum.org/EIPS/eip-161 - let is_non_existent_account = block(self.ethereum_account_map_or(address, true, |a| { - a.trx_count == 0 && a.balance == 0 && a.code_size == 0 - })); + let is_non_existent_account = self + .ethereum_account_map_or(address, true, |a| { + a.trx_count == 0 && a.balance == 0 && a.code_size == 0 + }) + .await; if is_non_existent_account { return <[u8; 32]>::default(); } // return empty hash(&[]) as a default value, or code's hash if contract exists - block( - self.ethereum_contract_map_or(address, hash(&[]).to_bytes(), |c| { - hash(&c.code()).to_bytes() - }), - ) + self.ethereum_contract_map_or(address, hash(&[]).to_bytes(), |c| { + hash(&c.code()).to_bytes() + }) + .await } - fn code(&self, address: &Address) -> evm_loader::evm::Buffer { + async fn code(&self, address: &Address) -> evm_loader::evm::Buffer { use evm_loader::evm::Buffer; info!("code {address}"); - block( - self.ethereum_contract_map_or(address, Buffer::empty(), |c| { - self.state_overrides - .as_ref() - .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) - .map_or_else( - || Buffer::from_slice(&c.code()), - |code| Buffer::from_slice(&code.0), - ) - }), - ) + self.ethereum_contract_map_or(address, Buffer::empty(), |c| { + self.state_overrides + .as_ref() + .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) + .map_or_else( + || Buffer::from_slice(&c.code()), + |code| Buffer::from_slice(&code.0), + ) + }) + .await } - fn generation(&self, address: &Address) -> u32 { - let value = block(self.ethereum_account_map_or(address, 0_u32, |c| c.generation)); + async fn generation(&self, address: &Address) -> u32 { + let value = self + .ethereum_account_map_or(address, 0_u32, |c| c.generation) + .await; info!("account generation {address} - {value}"); value } - fn storage(&self, address: &Address, index: &U256) -> [u8; 32] { + async fn storage(&self, address: &Address, index: &U256) -> [u8; 32] { if let Some(account_overrides) = &self.state_overrides { if let Some(account_override) = account_overrides.get(address) { match (&account_override.state, &account_override.state_diff) { @@ -623,11 +625,10 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } let value = if *index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) { let index: usize = index.as_usize() * 32; - block( - self.ethereum_contract_map_or(address, <[u8; 32]>::default(), |c| { - c.storage()[index..index + 32].try_into().unwrap() - }), - ) + self.ethereum_contract_map_or(address, <[u8; 32]>::default(), |c| { + c.storage()[index..index + 32].try_into().unwrap() + }) + .await } else { let subindex = (index & 0xFF).as_u8(); let index = index & !U256::new(0xFF); @@ -635,9 +636,12 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { let (base, _) = address.find_solana_address(self.program_id()); let storage_address = EthereumStorageAddress::new(self.program_id(), &base, &index); - block(self.add_solana_account(*storage_address.pubkey(), false)); + self.add_solana_account(*storage_address.pubkey(), false) + .await; - let rpc_response = block(self.get_account(storage_address.pubkey())) + let rpc_response = self + .get_account(storage_address.pubkey()) + .await .expect("Error querying account from Solana"); if let Some(mut account) = rpc_response { @@ -650,7 +654,7 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { .expect("EthereumAccount ctor error"); if (storage.address != *address) || (storage.index != index) - || (storage.generation != self.generation(address)) + || (storage.generation != self.generation(address).await) { debug!("storage collision"); <[u8; 32]>::default() @@ -669,8 +673,9 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { value } - fn solana_account_space(&self, address: &Address) -> Option { - block(self.ethereum_account_map_or(address, None, |account| Some(account.info.data_len()))) + async fn solana_account_space(&self, address: &Address) -> Option { + self.ethereum_account_map_or(address, None, |account| Some(account.info.data_len())) + .await } fn chain_id(&self) -> u64 { @@ -679,7 +684,7 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { self.chain_id } - fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { + async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { info!("clone_solana_account {}", address); if address == &FAKE_OPERATOR { @@ -694,9 +699,11 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { rent_epoch: 0, } } else { - block(self.add_solana_account(*address, false)); + self.add_solana_account(*address, false).await; - let mut account = block(self.get_account(address)) + let mut account = self + .get_account(address) + .await .unwrap_or_default() .unwrap_or_default(); let info = account_info(address, &mut account); @@ -705,13 +712,15 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } } - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R, { - block(self.add_solana_account(*address, false)); + self.add_solana_account(*address, false).await; - let mut account = block(self.get_account(address)) + let mut account = self + .get_account(address) + .await .unwrap_or_default() .unwrap_or_default(); let info = account_info(address, &mut account); diff --git a/evm_loader/lib/src/commands/collect_treasury.rs b/evm_loader/lib/src/commands/collect_treasury.rs index 7e2dcd0de..ad9130c0b 100644 --- a/evm_loader/lib/src/commands/collect_treasury.rs +++ b/evm_loader/lib/src/commands/collect_treasury.rs @@ -21,7 +21,7 @@ pub struct CollectTreasuryReturn { pub balance: u64, } -pub async fn execute(config: &Config, context: &Context) -> NeonResult { +pub async fn execute(config: &Config, context: &Context<'_>) -> NeonResult { let neon_params = read_elf_parameters_from_account(config, context).await?; let signer = context.signer()?; diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 9a1a5b3a5..140f0c6bf 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -16,7 +16,7 @@ use evm_loader::{ types::{Address, Transaction}, }; -use crate::types::{block, TxParams}; +use crate::types::TxParams; use crate::{ account_storage::{EmulatorAccountStorage, NeonAccount, SolanaAccount}, errors::NeonError, @@ -138,11 +138,8 @@ pub async fn execute( None, ) .await?; - let accounts = block(storage.accounts.read()).values().cloned().collect(); - let solana_accounts = block(storage.solana_accounts.read()) - .values() - .cloned() - .collect(); + let accounts = storage.accounts.borrow().values().cloned().collect(); + let solana_accounts = storage.solana_accounts.borrow().values().cloned().collect(); Ok(EmulationResultWithAccounts { accounts, @@ -221,9 +218,10 @@ pub(crate) async fn emulate_trx<'a>( }) .collect(); evm_loader::types::TransactionPayload::AccessList(evm_loader::types::AccessListTx { - nonce: tx_params - .nonce - .unwrap_or_else(|| storage.nonce(&tx_params.from)), + nonce: match tx_params.nonce { + Some(nonce) => nonce, + None => storage.nonce(&tx_params.from).await, + }, gas_price: U256::ZERO, gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), target: tx_params.to, @@ -237,9 +235,10 @@ pub(crate) async fn emulate_trx<'a>( }) } else { evm_loader::types::TransactionPayload::Legacy(evm_loader::types::LegacyTx { - nonce: tx_params - .nonce - .unwrap_or_else(|| storage.nonce(&tx_params.from)), + nonce: match tx_params.nonce { + Some(nonce) => nonce, + None => storage.nonce(&tx_params.from).await, + }, gas_price: U256::ZERO, gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), target: tx_params.to, @@ -260,9 +259,9 @@ pub(crate) async fn emulate_trx<'a>( signed_hash: <[u8; 32]>::default(), }; - let mut evm = Machine::new(&mut trx, tx_params.from, &mut backend, tracer)?; + let mut evm = Machine::new(&mut trx, tx_params.from, &mut backend, tracer).await?; - let (result, steps_executed) = evm.execute(step_limit, &mut backend)?; + let (result, steps_executed) = evm.execute(step_limit, &mut backend).await?; if result == ExitStatus::StepLimit { return Err(NeonError::TooManySteps); } @@ -274,13 +273,13 @@ pub(crate) async fn emulate_trx<'a>( debug!("Execute done, result={exit_status:?}"); debug!("{steps_executed} steps executed"); - let accounts_operations = storage.calc_accounts_operations(&actions); + let accounts_operations = storage.calc_accounts_operations(&actions).await; let max_iterations = (steps_executed + (EVM_STEPS_MIN - 1)) / EVM_STEPS_MIN; let steps_gas = max_iterations * (LAMPORTS_PER_SIGNATURE + PAYMENT_TO_TREASURE); let begin_end_gas = 2 * LAMPORTS_PER_SIGNATURE; - let actions_gas = block(storage.apply_actions(&actions)); - let accounts_gas = block(storage.apply_accounts_operations(accounts_operations)); + let actions_gas = storage.apply_actions(&actions).await; + let accounts_gas = storage.apply_accounts_operations(accounts_operations).await; info!("Gas - steps: {steps_gas}, actions: {actions_gas}, accounts: {accounts_gas}"); Ok(evm_loader::evm::tracing::EmulationResult { diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 7e5f039d1..882a96a98 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -16,7 +16,7 @@ pub struct CachedElfParams { } impl CachedElfParams { - pub async fn new(config: &Config, context: &Context) -> Self { + pub async fn new(config: &Config, context: &Context<'_>) -> Self { Self { elf_params: read_elf_parameters_from_account(config, context) .await @@ -143,7 +143,7 @@ pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { pub async fn read_elf_parameters_from_account( config: &Config, - context: &Context, + context: &Context<'_>, ) -> Result { let (_, program_data) = read_program_data_from_account(config, context, &config.evm_loader).await?; @@ -152,7 +152,7 @@ pub async fn read_elf_parameters_from_account( pub async fn read_program_data_from_account( config: &Config, - context: &Context, + context: &Context<'_>, evm_loader: &Pubkey, ) -> Result<(Option, Vec), NeonError> { let account = context @@ -226,14 +226,14 @@ fn read_program_params_from_file( async fn read_program_params_from_account( config: &Config, - context: &Context, + context: &Context<'_>, ) -> NeonResult { read_elf_parameters_from_account(config, context).await } pub async fn execute( config: &Config, - context: &Context, + context: &Context<'_>, program_location: Option<&str>, ) -> NeonResult { if let Some(program_location) = program_location { diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 44261324d..bd8f02632 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -15,7 +15,6 @@ use evm_loader::{ use crate::{ account_storage::{account_info, EmulatorAccountStorage}, rpc::Rpc, - types::block, NeonResult, }; @@ -52,7 +51,7 @@ pub async fn execute( let address = EthereumStorageAddress::new(evm_loader, account_data.info.key, &index); - if let Ok(mut account) = block(rpc_client.get_account(address.pubkey())) { + if let Ok(mut account) = rpc_client.get_account(address.pubkey()).await { if solana_sdk::system_program::check_id(&account.owner) { Default::default() } else { diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 1c45090b9..018b2443d 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::rc::Rc; use serde::{Deserialize, Serialize}; @@ -103,7 +103,7 @@ fn read_keys_dir(keys_dir: &str) -> Result, NeonError> #[allow(clippy::too_many_lines)] pub async fn execute( config: &Config, - context: &Context, + context: &Context<'_>, send_trx: bool, force: bool, keys_dir: Option<&str>, @@ -116,13 +116,13 @@ pub async fn execute( send_trx, force ); - let second_signer: Arc = Arc::from(context.signer()?); - let fee_payer = config - .fee_payer - .as_ref() - .map_or_else(move || second_signer, |v| v.clone()); - let executor = Arc::new(TransactionExecutor::new( - context.rpc_client.clone(), + let second_signer: &dyn Signer = &*context.signer()?; + let fee_payer: &dyn Signer = match config.fee_payer.as_ref() { + Some(fee_payer) => fee_payer, + None => second_signer, + }; + let executor = Rc::new(TransactionExecutor::new( + context.rpc_client, fee_payer, send_trx, )); @@ -329,13 +329,14 @@ pub async fn execute( executor.checkpoint(context.rpc_client.commitment()).await?; - let stats = executor.stats.read().await; - info!("Stats: {:?}", stats); + { + let stats = executor.stats.borrow(); + info!("Stats: {:?}", stats); + } let signatures = executor .signatures - .read() - .await + .borrow() .iter() .map(|s| bs58::encode(s).into_string()) .collect::>(); @@ -344,6 +345,8 @@ pub async fn execute( transactions: signatures, }; + let stats = executor.stats.borrow(); + if stats.total_objects == stats.corrected_objects { Ok(result) } else if stats.invalid_objects == 0 { diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 7a7061fc6..50a5979ad 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,5 +1,5 @@ use std::fmt::{Display, Formatter}; -use std::sync::Arc; +use std::rc::Rc; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -44,14 +44,13 @@ pub async fn trace_transaction( solana_accounts, &trace_call_config.block_overrides, trace_call_config.state_overrides, - Some(Arc::clone(&tracer)), + Some(Rc::clone(&tracer)), ) .await?; - Ok(Arc::try_unwrap(tracer) + Ok(Rc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() - .expect("Poisoned RwLock") .into_traces(emulation_result)) } @@ -115,13 +114,12 @@ async fn trace_trx<'a>( storage, chain_id, steps, - Some(Arc::clone(&tracer)), + Some(Rc::clone(&tracer)), ) .await?; - Ok(Arc::try_unwrap(tracer) + Ok(Rc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() - .expect("Poisoned RwLock") .into_traces(emulation_result)) } diff --git a/evm_loader/lib/src/commands/transaction_executor.rs b/evm_loader/lib/src/commands/transaction_executor.rs index f195f9f71..b57ec31e5 100644 --- a/evm_loader/lib/src/commands/transaction_executor.rs +++ b/evm_loader/lib/src/commands/transaction_executor.rs @@ -1,7 +1,7 @@ -use std::{future::Future, sync::Arc}; +use std::cell::RefCell; +use std::future::Future; use serde::{Deserialize, Serialize}; -use tokio::sync::RwLock; use { crate::{errors::NeonError, rpc}, @@ -45,21 +45,21 @@ impl Stats { self.created_objects += 1; } } -pub struct TransactionExecutor { - pub client: Arc, +pub struct TransactionExecutor<'a, 'b> { + pub client: &'a dyn rpc::Rpc, pub send_trx: bool, - pub signatures: RwLock>, - pub stats: RwLock, - pub fee_payer: Arc, + pub signatures: RefCell>, + pub stats: RefCell, + pub fee_payer: &'b dyn Signer, } -impl TransactionExecutor { - pub fn new(client: Arc, fee_payer: Arc, send_trx: bool) -> Self { +impl<'a, 'b> TransactionExecutor<'a, 'b> { + pub fn new(client: &'a dyn rpc::Rpc, fee_payer: &'b dyn Signer, send_trx: bool) -> Self { Self { client, send_trx, - signatures: RwLock::new(vec![]), - stats: RwLock::new(Stats::default()), + signatures: RefCell::new(vec![]), + stats: RefCell::new(Stats::default()), fee_payer, } } @@ -96,9 +96,10 @@ impl TransactionExecutor { } } + #[allow(clippy::await_holding_refcell_ref)] pub async fn checkpoint(&self, commitment: CommitmentConfig) -> Result<(), NeonError> { let recent_blockhash = self.client.get_latest_blockhash().await?; - for sig in self.signatures.read().await.iter() { + for sig in self.signatures.borrow().iter() { self.client .confirm_transaction_with_spinner(sig, &recent_blockhash, commitment) .await?; @@ -115,7 +116,7 @@ impl TransactionExecutor { Transaction::new_with_payer(instructions, Some(&self.fee_payer.pubkey())); let blockhash = self.client.get_latest_blockhash().await?; - transaction.try_partial_sign(&[self.fee_payer.as_ref()], blockhash)?; + transaction.try_partial_sign(&[self.fee_payer], blockhash)?; transaction.try_sign(signing_keypairs, blockhash)?; Ok(transaction) @@ -161,7 +162,7 @@ impl TransactionExecutor { match verify(data.clone()).await { Ok(None) => { info!("{}: correct", name); - self.stats.write().await.inc_corrected_objects(); + self.stats.borrow_mut().inc_corrected_objects(); } Ok(Some(transaction)) => { if self.send_trx { @@ -169,24 +170,24 @@ impl TransactionExecutor { match result { Ok(signature) => { warn!("{}: updated in trx {}", name, signature); - self.signatures.write().await.push(signature); - self.stats.write().await.inc_modified_objects(); + self.signatures.borrow_mut().push(signature); + self.stats.borrow_mut().inc_modified_objects(); return Ok(Some(signature)); } Err(error) => { error!("{}: failed update with {}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); return Err(error); } }; }; debug!("{}: {:?}", name, transaction); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); warn!("{}: will be updated", name); } Err(error) => { error!("{}: wrong object {:?}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); if self.send_trx { return Err(error); } @@ -196,7 +197,7 @@ impl TransactionExecutor { match create().await { Ok(None) => { info!("{}: missed ok", name); - self.stats.write().await.inc_corrected_objects(); + self.stats.borrow_mut().inc_corrected_objects(); } Ok(Some(transaction)) => { if self.send_trx { @@ -204,24 +205,24 @@ impl TransactionExecutor { match result { Ok(signature) => { warn!("{}: created in trx {}", name, signature); - self.signatures.write().await.push(signature); - self.stats.write().await.inc_created_objects(); + self.signatures.borrow_mut().push(signature); + self.stats.borrow_mut().inc_created_objects(); return Ok(Some(signature)); } Err(error) => { error!("{}: failed create with {}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); return Err(error); } }; }; debug!("{}: {:?}", name, transaction); warn!("{}: will be created", name); - self.stats.write().await.inc_created_objects(); + self.stats.borrow_mut().inc_created_objects(); } Err(error) => { error!("{}: can't be created: {:?}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); if self.send_trx { return Err(error); } diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index f1293ff08..ab12bc955 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,4 +1,4 @@ -use std::{env, str::FromStr, sync::Arc}; +use std::{env, str::FromStr}; use crate::{types::ChDbConfig, NeonError}; use serde::{Deserialize, Serialize}; @@ -11,7 +11,7 @@ use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature: #[derive(Debug)] pub struct Config { pub evm_loader: Pubkey, - pub fee_payer: Option>, + pub fee_payer: Option, pub commitment: CommitmentConfig, pub solana_cli_config: solana_cli_config::Config, pub db_config: Option, @@ -53,8 +53,7 @@ pub fn create_from_api_config(api_config: &APIOptions) -> Result = Option::from(api_config.db_config.clone()); diff --git a/evm_loader/lib/src/context.rs b/evm_loader/lib/src/context.rs index 0d2b8c4b4..91793531e 100644 --- a/evm_loader/lib/src/context.rs +++ b/evm_loader/lib/src/context.rs @@ -1,11 +1,8 @@ -use std::sync::Arc; - use crate::{ rpc::{self}, Config, NeonError, }; use solana_clap_utils::keypair::signer_from_path; -use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::signature::Signer; pub fn truncate_0x(in_str: &str) -> &str { @@ -16,44 +13,17 @@ pub fn truncate_0x(in_str: &str) -> &str { } } -pub struct Context { - pub rpc_client: Arc, - signer_config: Arc, +pub struct Context<'a> { + pub rpc_client: &'a dyn rpc::Rpc, + signer_config: &'a Config, } -impl Context { +impl<'a> Context<'a> { pub fn signer(&self) -> Result, NeonError> { - build_signer(&self.signer_config) - } - - pub async fn new_from_config( - config: Arc, - slot: Option, - ) -> Result { - let rpc_client: Arc = if let Some(slot) = slot { - Arc::new( - rpc::CallDbClient::new( - crate::types::TracerDb::new( - config.db_config.as_ref().expect("db-config not found"), - ), - slot, - ) - .await?, - ) - } else { - Arc::new(RpcClient::new_with_commitment( - config.json_rpc_url.clone(), - config.commitment, - )) - }; - - Ok(Self { - rpc_client, - signer_config: config.clone(), - }) + build_signer(self.signer_config) } - pub fn new(rpc_client: Arc, signer_config: Arc) -> Self { + pub fn new(rpc_client: &'a dyn rpc::Rpc, signer_config: &'a Config) -> Context<'a> { Self { rpc_client, signer_config, diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 132e6e5b2..d8c20a32e 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -78,8 +78,6 @@ pub enum NeonError { TxParametersParsingError(String), #[error("AddrParseError. {0:?}")] AddrParseError(#[from] AddrParseError), - #[error("AxumError. {0:?}")] - AxumError(#[from] axum::Error), #[error("SolanaClientError. {0:?}")] SolanaClientError(solana_client::client_error::ClientError), /// Environment Error @@ -117,7 +115,6 @@ impl NeonError { NeonError::PubkeyError(_) => 116, NeonError::EvmError(_) => 117, NeonError::AddrParseError(_) => 118, - NeonError::AxumError(_) => 119, NeonError::SolanaClientError(_) => 120, NeonError::EvmLoaderNotSpecified => 201, NeonError::KeypairNotSpecified => 202, diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index a84aa7dce..29a972f41 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -41,7 +41,7 @@ impl CallDbClient { } } -#[async_trait] +#[async_trait(?Send)] impl Rpc for CallDbClient { fn commitment(&self) -> CommitmentConfig { CommitmentConfig::default() diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index d6fcc1f7c..30690ff19 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -28,8 +28,8 @@ use solana_transaction_status::{ }; use std::any::Any; -#[async_trait] -pub trait Rpc: Send + Sync { +#[async_trait(?Send)] +pub trait Rpc { fn commitment(&self) -> CommitmentConfig; async fn confirm_transaction_with_spinner( &self, diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index ab4cbab12..727698d83 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -20,7 +20,7 @@ use solana_transaction_status::{ }; use std::any::Any; -#[async_trait] +#[async_trait(?Send)] impl Rpc for RpcClient { fn commitment(&self) -> CommitmentConfig { self.commitment() diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 69e8099ff..6cc2322b3 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -3,11 +3,8 @@ pub mod tracer_ch_common; mod tracer_ch_db; pub use evm_loader::types::Address; -use lazy_static::lazy_static; use solana_sdk::pubkey::Pubkey; use std::str::FromStr; -use tokio::runtime::Runtime; -use tokio::task::block_in_place; pub use tracer_ch_db::ClickHouseDb as TracerDb; use evm_loader::evm::tracing::TraceCallConfig; @@ -47,20 +44,6 @@ pub struct TransactionParams { pub trace_config: Option, } -lazy_static! { - pub static ref RT: Runtime = Runtime::new().unwrap(); -} - -pub fn block(f: Fu) -> Fu::Output -where - Fu: std::future::Future, -{ - match tokio::runtime::Handle::try_current() { - Ok(handle) => block_in_place(|| handle.block_on(f)), - Err(_) => RT.block_on(f), - } -} - #[derive(Debug, Default, Clone, Copy)] pub struct PubkeyBase58(pub Pubkey); diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 0cc9bfbb6..f60cf9c2b 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -21,14 +21,12 @@ use std::{ Ord, Ordering::{Equal, Greater, Less}, }, - sync::Arc, time::Instant, }; -#[allow(dead_code)] #[derive(Clone)] pub struct ClickHouseDb { - pub client: Arc, + pub client: Client, } impl ClickHouseDb { @@ -45,9 +43,7 @@ impl ClickHouseDb { .with_password(password), }; - ClickHouseDb { - client: Arc::new(client), - } + ClickHouseDb { client } } // return value is not used for tracer methods diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 6c8e1c10f..f1fab8ba7 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -34,8 +34,6 @@ test-bpf = [] custom-heap = [] default = ["custom-heap"] -tracing = ["serde_json"] - [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } @@ -58,6 +56,12 @@ ethnum = { version = "1.4", default-features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } +maybe-async = "0.2.7" +async-trait = { version = "0.1.73", optional = true } + +[target.'cfg(target_os = "solana")'.dependencies.maybe-async] +version = "0.2.7" +features = ["is_sync"] [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index b2b47dbcf..27e8c3978 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -1,17 +1,25 @@ -use crate::account::{EthereumAccount, EthereumStorage}; +use crate::account::EthereumAccount; use crate::executor::{Action, OwnedAccountInfo}; use crate::types::Address; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::account_info::AccountInfo; -use solana_program::clock::Clock; +#[cfg(target_os = "solana")] +use { + crate::account::EthereumStorage, solana_program::clock::Clock, std::cell::RefCell, + std::collections::HashSet, +}; + use solana_program::pubkey::Pubkey; use solana_program::slot_history::Slot; -use std::cell::RefCell; use std::cmp::Ordering; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; +#[cfg(target_os = "solana")] mod apply; +#[cfg(target_os = "solana")] mod backend; +#[cfg(target_os = "solana")] mod base; #[derive(Debug)] @@ -29,6 +37,7 @@ pub enum AccountsReadiness { NeedMoreReallocations, } +#[cfg(target_os = "solana")] pub struct ProgramAccountStorage<'a> { program_id: &'a Pubkey, operator: &'a Pubkey, @@ -45,6 +54,7 @@ pub struct ProgramAccountStorage<'a> { /// Account storage /// Trait to access account info +#[maybe_async(?Send)] pub trait AccountStorage { /// Get `NEON` token mint fn neon_token_mint(&self) -> &Pubkey; @@ -60,34 +70,34 @@ pub trait AccountStorage { /// Get block timestamp fn block_timestamp(&self) -> U256; /// Get block hash - fn block_hash(&self, number: u64) -> [u8; 32]; + async fn block_hash(&self, number: u64) -> [u8; 32]; /// Get chain id fn chain_id(&self) -> u64; /// Check if ethereum account exists - fn exists(&self, address: &Address) -> bool; + async fn exists(&self, address: &Address) -> bool; /// Get account nonce - fn nonce(&self, address: &Address) -> u64; + async fn nonce(&self, address: &Address) -> u64; /// Get account balance - fn balance(&self, address: &Address) -> U256; + async fn balance(&self, address: &Address) -> U256; /// Get code size - fn code_size(&self, address: &Address) -> usize; + async fn code_size(&self, address: &Address) -> usize; /// Get code hash - fn code_hash(&self, address: &Address) -> [u8; 32]; + async fn code_hash(&self, address: &Address) -> [u8; 32]; /// Get code data - fn code(&self, address: &Address) -> crate::evm::Buffer; + async fn code(&self, address: &Address) -> crate::evm::Buffer; /// Get contract generation - fn generation(&self, address: &Address) -> u32; + async fn generation(&self, address: &Address) -> u32; /// Get data from storage - fn storage(&self, address: &Address, index: &U256) -> [u8; 32]; + async fn storage(&self, address: &Address, index: &U256) -> [u8; 32]; /// Clone existing solana account - fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo; + async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo; /// Map existing solana account - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R; @@ -97,9 +107,9 @@ pub trait AccountStorage { } /// Solana account data len - fn solana_account_space(&self, address: &Address) -> Option; + async fn solana_account_space(&self, address: &Address) -> Option; - fn calc_accounts_operations(&self, actions: &[Action]) -> AccountsOperations { + async fn calc_accounts_operations(&self, actions: &[Action]) -> AccountsOperations { let mut accounts = HashMap::new(); for action in actions { let (address, code_size) = match action { @@ -117,27 +127,28 @@ pub trait AccountStorage { accounts.insert(address, space_needed); } - accounts - .into_iter() - .filter_map( - |(address, space_needed)| match self.solana_account_space(address) { - None => Some(( - *address, - AccountOperation::Create { - space: space_needed, - }, - )), - Some(space_current) if space_current < space_needed => Some(( - *address, - AccountOperation::Resize { - from: space_current, - to: space_needed, - }, - )), - _ => None, - }, - ) - .collect() + let mut result = AccountsOperations::new(); + + for (address, space_needed) in accounts { + match self.solana_account_space(address).await { + None => result.push(( + *address, + AccountOperation::Create { + space: space_needed, + }, + )), + Some(space_current) if space_current < space_needed => result.push(( + *address, + AccountOperation::Resize { + from: space_current, + to: space_needed, + }, + )), + _ => (), + } + } + + result } } diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 11cc85f1a..56efcb7e9 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -1,31 +1,33 @@ use super::{Buffer, Context}; use crate::{error::Result, types::Address}; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +#[maybe_async(?Send)] pub trait Database { fn chain_id(&self) -> U256; - fn nonce(&self, address: &Address) -> Result; + async fn nonce(&self, address: &Address) -> Result; fn increment_nonce(&mut self, address: Address) -> Result<()>; - fn balance(&self, address: &Address) -> Result; - fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()>; + async fn balance(&self, address: &Address) -> Result; + async fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()>; - fn code_size(&self, address: &Address) -> Result; - fn code_hash(&self, address: &Address) -> Result<[u8; 32]>; - fn code(&self, address: &Address) -> Result; + async fn code_size(&self, address: &Address) -> Result; + async fn code_hash(&self, address: &Address) -> Result<[u8; 32]>; + async fn code(&self, address: &Address) -> Result; fn set_code(&mut self, address: Address, code: Buffer) -> Result<()>; fn selfdestruct(&mut self, address: Address) -> Result<()>; - fn storage(&self, address: &Address, index: &U256) -> Result<[u8; 32]>; + async fn storage(&self, address: &Address, index: &U256) -> Result<[u8; 32]>; fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; - fn block_hash(&self, number: U256) -> Result<[u8; 32]>; + async fn block_hash(&self, number: U256) -> Result<[u8; 32]>; fn block_number(&self) -> Result; fn block_timestamp(&self) -> Result; - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R; @@ -33,7 +35,7 @@ pub trait Database { fn revert_snapshot(&mut self); fn commit_snapshot(&mut self); - fn precompile_extension( + async fn precompile_extension( &mut self, context: &Context, address: &Address, diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index ce9c40c6d..2ccb671fe 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -4,7 +4,7 @@ use std::ops::Range; use solana_program::program_memory::{sol_memcpy, sol_memset}; use crate::error::Error; -#[cfg(feature = "tracing")] +#[cfg(not(target_os = "solana"))] use crate::evm::tracing::TracerTypeOpt; use super::utils::checked_next_multiple_of_32; @@ -20,22 +20,22 @@ pub struct Memory { data: *mut u8, capacity: usize, size: usize, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, } impl Memory { - pub fn new(#[cfg(feature = "tracing")] tracer: TracerTypeOpt) -> Self { + pub fn new(#[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt) -> Self { Self::with_capacity( MEMORY_CAPACITY, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, ) } pub fn with_capacity( capacity: usize, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Self { unsafe { let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); @@ -48,7 +48,7 @@ impl Memory { data, capacity, size: 0, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, } } @@ -70,13 +70,13 @@ impl Memory { data, capacity, size: v.len(), - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: None, } } } - #[allow(dead_code)] + #[cfg(not(target_os = "solana"))] pub fn to_vec(&self) -> Vec { let slice = unsafe { std::slice::from_raw_parts(self.data, self.size) }; slice.to_vec() diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 09505121f..9e270e81b 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -5,12 +5,13 @@ use std::{marker::PhantomData, ops::Range}; use ethnum::U256; +use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; use solana_program::log::sol_log_data; pub use buffer::Buffer; -#[cfg(feature = "tracing")] +#[cfg(not(target_os = "solana"))] use crate::evm::tracing::TracerTypeOpt; use crate::{ error::{build_revert_message, Error, Result}, @@ -27,22 +28,22 @@ mod opcode; mod opcode_table; mod precompile; mod stack; -#[cfg(feature = "tracing")] +#[cfg(not(target_os = "solana"))] pub mod tracing; mod utils; macro_rules! tracing_event { ($self:ident, $x:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if let Some(tracer) = &$self.tracer { - tracer.write().expect("Poisoned RwLock").event($x); + tracer.borrow_mut().event($x); } }; ($self:ident, $condition:expr, $x:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if let Some(tracer) = &$self.tracer { if $condition { - tracer.write().expect("Poisoned RwLock").event($x); + tracer.borrow_mut().event($x); } } }; @@ -50,11 +51,10 @@ macro_rules! tracing_event { macro_rules! trace_end_step { ($self:ident, $return_data:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if let Some(tracer) = &$self.tracer { tracer - .write() - .expect("Poisoned RwLock") + .borrow_mut() .event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: $return_data, @@ -62,7 +62,7 @@ macro_rules! trace_end_step { } }; ($self:ident, $condition:expr; $return_data_getter:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if $condition { trace_end_step!($self, $return_data_getter) } @@ -153,8 +153,8 @@ pub struct Machine { #[serde(skip)] phantom: PhantomData<*const B>, + #[cfg(not(target_os = "solana"))] #[serde(skip)] - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, } @@ -167,6 +167,7 @@ impl Machine { cursor.position().try_into().map_err(Error::from) } + #[cfg(target_os = "solana")] pub fn deserialize_from(buffer: &[u8], backend: &B) -> Result { fn reinit_buffer(buffer: &mut Buffer, backend: &B) { if let Some((key, range)) = buffer.uninit_data() { @@ -175,13 +176,16 @@ impl Machine { } } - fn reinit_machine(machine: &mut Machine, backend: &B) { - reinit_buffer(&mut machine.call_data, backend); - reinit_buffer(&mut machine.execution_code, backend); - reinit_buffer(&mut machine.return_data, backend); + fn reinit_machine(mut machine: &mut Machine, backend: &B) { + loop { + reinit_buffer(&mut machine.call_data, backend); + reinit_buffer(&mut machine.execution_code, backend); + reinit_buffer(&mut machine.return_data, backend); - if let Some(parent) = &mut machine.parent { - reinit_machine(parent, backend); + match &mut machine.parent { + None => break, + Some(parent) => machine = parent, + } } } @@ -191,13 +195,14 @@ impl Machine { Ok(evm) } - pub fn new( + #[maybe_async] + pub async fn new( trx: &mut Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { - let origin_nonce = backend.nonce(&origin)?; + let origin_nonce = backend.nonce(&origin).await?; if origin_nonce == u64::MAX { return Err(Error::NonceOverflow(origin)); @@ -217,11 +222,11 @@ impl Machine { } } - if backend.balance(&origin)? < trx.value() { + if backend.balance(&origin).await? < trx.value() { return Err(Error::InsufficientBalance(origin, trx.value())); } - if backend.code_size(&origin)? != 0 { + if backend.code_size(&origin).await? != 0 { return Err(Error::SenderHasDeployedCode(origin)); } @@ -230,25 +235,28 @@ impl Machine { trx, origin, backend, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, ) + .await } else { Self::new_create( trx, origin, backend, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, ) + .await } } - fn new_call( + #[maybe_async] + async fn new_call( trx: &mut Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { assert!(trx.target().is_some()); @@ -258,9 +266,9 @@ impl Machine { backend.increment_nonce(origin)?; backend.snapshot(); - backend.transfer(origin, target, trx.value())?; + backend.transfer(origin, target, trx.value()).await?; - let execution_code = backend.code(&target)?; + let execution_code = backend.code(&target).await?; Ok(Self { origin, @@ -277,11 +285,11 @@ impl Machine { return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), memory: Memory::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), pc: 0_usize, @@ -289,23 +297,24 @@ impl Machine { reason: Reason::Call, parent: None, phantom: PhantomData, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, }) } - fn new_create( + #[maybe_async] + async fn new_create( trx: &mut Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { assert!(trx.target().is_none()); let target = Address::from_create(&origin, trx.nonce()); sol_log_data(&[b"ENTER", b"CREATE", target.as_bytes()]); - if (backend.nonce(&target)? != 0) || (backend.code_size(&target)? != 0) { + if (backend.nonce(&target).await? != 0) || (backend.code_size(&target).await? != 0) { return Err(Error::DeployToExistingAccount(target, origin)); } @@ -313,7 +322,7 @@ impl Machine { backend.snapshot(); backend.increment_nonce(target)?; - backend.transfer(origin, target, trx.value())?; + backend.transfer(origin, target, trx.value()).await?; Ok(Self { origin, @@ -328,11 +337,11 @@ impl Machine { return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), memory: Memory::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), pc: 0_usize, @@ -342,12 +351,13 @@ impl Machine { call_data: Buffer::empty(), parent: None, phantom: PhantomData, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, }) } - pub fn execute(&mut self, step_limit: u64, backend: &mut B) -> Result<(ExitStatus, u64)> { + #[maybe_async] + pub async fn execute(&mut self, step_limit: u64, backend: &mut B) -> Result<(ExitStatus, u64)> { assert!(self.execution_code.is_initialized()); assert!(self.call_data.is_initialized()); assert!(self.return_data.is_initialized()); @@ -386,14 +396,12 @@ impl Machine { } ); - // SAFETY: OPCODES.len() == 256, opcode <= 255 - let (_, opcode_fn) = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; - - let opcode_result = match opcode_fn(self, backend) { + let opcode_result = match self.execute_opcode(backend, opcode).await { Ok(result) => result, Err(e) => { let message = build_revert_message(&e.to_string()); - self.opcode_revert_impl(Buffer::from_slice(&message), backend)? + self.opcode_revert_impl(Buffer::from_slice(&message), backend) + .await? } }; @@ -442,11 +450,11 @@ impl Machine { return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] self.tracer.clone(), ), memory: Memory::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] self.tracer.clone(), ), pc: 0_usize, @@ -454,7 +462,7 @@ impl Machine { reason, parent: None, phantom: PhantomData, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: self.tracer.clone(), }; diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 928ad0349..f1f8c9b48 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,5 +1,6 @@ /// use ethnum::{I256, U256}; +use maybe_async::maybe_async; use solana_program::log::sol_log_data; use super::{database::Database, tracing_event, Context, Machine, Reason}; @@ -20,9 +21,11 @@ pub enum Action { Noop, } +#[allow(clippy::unused_async)] impl Machine { /// Unknown instruction - pub fn opcode_unknown(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_unknown(&mut self, _backend: &mut B) -> Result { Err(Error::UnknownOpcode( self.context.contract, self.execution_code[self.pc], @@ -30,7 +33,8 @@ impl Machine { } /// (u)int256 addition modulo 2**256 - pub fn opcode_add(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_add(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let c = a.wrapping_add(b); @@ -41,7 +45,8 @@ impl Machine { } /// (u)int256 multiplication modulo 2**256 - pub fn opcode_mul(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mul(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let c = a.wrapping_mul(b); @@ -52,7 +57,8 @@ impl Machine { } /// (u)int256 subtraction modulo 2**256 - pub fn opcode_sub(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sub(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let c = a.wrapping_sub(b); @@ -63,7 +69,8 @@ impl Machine { } /// uint256 division - pub fn opcode_div(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_div(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -78,7 +85,8 @@ impl Machine { } /// int256 division - pub fn opcode_sdiv(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sdiv(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; @@ -94,7 +102,8 @@ impl Machine { } /// uint256 modulus - pub fn opcode_mod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mod(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -109,7 +118,8 @@ impl Machine { } /// int256 modulus - pub fn opcode_smod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_smod(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; @@ -126,7 +136,8 @@ impl Machine { /// (u)int256 addition modulo M /// (a + b) % m /// - pub fn opcode_addmod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_addmod(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let m = self.stack.pop_u256()?; @@ -157,7 +168,8 @@ impl Machine { /// (u)int256 multiplication modulo M /// (a * b) % m /// - pub fn opcode_mulmod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mulmod(&mut self, _backend: &mut B) -> Result { let mut a = self.stack.pop_u256()?; let mut b = self.stack.pop_u256()?; let m = self.stack.pop_u256()?; @@ -202,7 +214,8 @@ impl Machine { /// uint256 exponentiation modulo 2**256 /// a ** b - pub fn opcode_exp(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_exp(&mut self, _backend: &mut B) -> Result { let mut a = self.stack.pop_u256()?; let mut b = self.stack.pop_u256()?; @@ -231,7 +244,8 @@ impl Machine { } /// sign extends x from (b + 1) * 8 bits to 256 bits. - pub fn opcode_signextend(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_signextend(&mut self, _backend: &mut B) -> Result { let b = self.stack.pop_u256()?; let x = self.stack.pop_u256()?; @@ -256,7 +270,8 @@ impl Machine { /// uint256 comparison /// a < b - pub fn opcode_lt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_lt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -267,7 +282,8 @@ impl Machine { /// uint256 comparison /// a > b - pub fn opcode_gt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -278,7 +294,8 @@ impl Machine { /// int256 comparison /// a < b - pub fn opcode_slt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_slt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; self.stack.push_bool(a < b)?; @@ -288,7 +305,8 @@ impl Machine { /// int256 comparison /// a > b - pub fn opcode_sgt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sgt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; self.stack.push_bool(a > b)?; @@ -298,7 +316,8 @@ impl Machine { /// (u)int256 equality /// a == b - pub fn opcode_eq(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_eq(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -309,7 +328,8 @@ impl Machine { /// (u)int256 is zero /// a == 0 - pub fn opcode_iszero(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_iszero(&mut self, _backend: &mut B) -> Result { let result = { let a = self.stack.pop_array()?; a == &[0_u8; 32] @@ -321,7 +341,8 @@ impl Machine { } /// 256-bit bitwise and - pub fn opcode_and(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_and(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -331,7 +352,8 @@ impl Machine { } /// 256-bit bitwise or - pub fn opcode_or(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_or(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -341,7 +363,8 @@ impl Machine { } /// 256-bit bitwise xor - pub fn opcode_xor(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_xor(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -351,7 +374,8 @@ impl Machine { } /// 256-bit bitwise not - pub fn opcode_not(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_not(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; self.stack.push_u256(!a)?; @@ -359,7 +383,8 @@ impl Machine { } /// ith byte of (u)int256 x, counting from most significant byte - pub fn opcode_byte(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_byte(&mut self, _backend: &mut B) -> Result { let result = { let i = self.stack.pop_u256()?; let x = self.stack.pop_array()?; @@ -377,7 +402,8 @@ impl Machine { } /// 256-bit shift left - pub fn opcode_shl(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_shl(&mut self, _backend: &mut B) -> Result { let shift = self.stack.pop_u256()?; let value = self.stack.pop_u256()?; @@ -391,7 +417,8 @@ impl Machine { } /// 256-bit shift right - pub fn opcode_shr(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_shr(&mut self, _backend: &mut B) -> Result { let shift = self.stack.pop_u256()?; let value = self.stack.pop_u256()?; @@ -405,7 +432,8 @@ impl Machine { } /// arithmetic int256 shift right - pub fn opcode_sar(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sar(&mut self, _backend: &mut B) -> Result { let (shift, value) = { let shift = self.stack.pop_u256()?; let value = self.stack.pop_i256()?; @@ -422,7 +450,8 @@ impl Machine { } /// hash = keccak256(memory[offset:offset+length]) - pub fn opcode_sha3(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sha3(&mut self, _backend: &mut B) -> Result { use solana_program::keccak::{hash, Hash}; let offset = self.stack.pop_usize()?; @@ -437,17 +466,19 @@ impl Machine { } /// address of the executing contract - pub fn opcode_address(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_address(&mut self, _backend: &mut B) -> Result { self.stack.push_address(&self.context.contract)?; Ok(Action::Continue) } /// address balance in wei - pub fn opcode_balance(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_balance(&mut self, backend: &mut B) -> Result { let balance = { let address = self.stack.pop_address()?; - backend.balance(address)? + backend.balance(address).await? }; self.stack.push_u256(balance)?; @@ -457,7 +488,8 @@ impl Machine { /// transaction origin address /// tx.origin - pub fn opcode_origin(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_origin(&mut self, _backend: &mut B) -> Result { self.stack.push_address(&self.origin)?; Ok(Action::Continue) @@ -465,7 +497,8 @@ impl Machine { /// message caller address /// msg.caller - pub fn opcode_caller(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_caller(&mut self, _backend: &mut B) -> Result { self.stack.push_address(&self.context.caller)?; Ok(Action::Continue) @@ -473,7 +506,8 @@ impl Machine { /// message funds in wei /// msg.value - pub fn opcode_callvalue(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_callvalue(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(self.context.value)?; Ok(Action::Continue) @@ -481,7 +515,8 @@ impl Machine { /// reads a (u)int256 from message data /// msg.data[i:i+32] - pub fn opcode_calldataload(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_calldataload(&mut self, _backend: &mut B) -> Result { let index = self.stack.pop_usize()?; if let Some(buffer) = self.call_data.get(index..index + 32) { @@ -502,14 +537,16 @@ impl Machine { /// message data length in bytes /// msg.data.size - pub fn opcode_calldatasize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_calldatasize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.call_data.len())?; Ok(Action::Continue) } /// copy message data to memory - pub fn opcode_calldatacopy(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_calldatacopy(&mut self, _backend: &mut B) -> Result { let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; @@ -522,14 +559,16 @@ impl Machine { /// length of the executing contract's code in bytes /// address(this).code.size - pub fn opcode_codesize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_codesize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.execution_code.len())?; Ok(Action::Continue) } /// copy executing contract's bytecode - pub fn opcode_codecopy(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_codecopy(&mut self, _backend: &mut B) -> Result { let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; @@ -542,7 +581,8 @@ impl Machine { /// gas price of the executing transaction, in wei per unit of gas /// tx.gasprice - pub fn opcode_gasprice(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gasprice(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(self.gas_price)?; Ok(Action::Continue) @@ -550,10 +590,11 @@ impl Machine { /// length of the contract bytecode at addr, in bytes /// address(addr).code.size - pub fn opcode_extcodesize(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_extcodesize(&mut self, backend: &mut B) -> Result { let code_size = { let address = self.stack.pop_address()?; - backend.code_size(address)? + backend.code_size(address).await? }; self.stack.push_usize(code_size)?; @@ -562,13 +603,14 @@ impl Machine { } /// copy contract's bytecode - pub fn opcode_extcodecopy(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_extcodecopy(&mut self, backend: &mut B) -> Result { let address = *self.stack.pop_address()?; let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; self.memory .write_buffer(memory_offset, length, &code, data_offset)?; @@ -577,14 +619,16 @@ impl Machine { } /// Byzantium hardfork, EIP-211: the size of the returned data from the last external call, in bytes - pub fn opcode_returndatasize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_returndatasize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.return_data.len())?; Ok(Action::Continue) } /// Byzantium hardfork, EIP-211: copy returned data - pub fn opcode_returndatacopy(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_returndatacopy(&mut self, _backend: &mut B) -> Result { let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; @@ -600,10 +644,11 @@ impl Machine { } /// Constantinople hardfork, EIP-1052: hash of the contract bytecode at addr - pub fn opcode_extcodehash(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_extcodehash(&mut self, backend: &mut B) -> Result { let code_hash = { let address = self.stack.pop_address()?; - backend.code_hash(address)? + backend.code_hash(address).await? }; self.stack.push_array(&code_hash)?; @@ -613,11 +658,12 @@ impl Machine { /// hash of the specific block, only valid for the 256 most recent blocks, excluding the current one /// Solana limits to 150 most recent blocks - pub fn opcode_blockhash(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_blockhash(&mut self, backend: &mut B) -> Result { let block_hash = { let block_number = self.stack.pop_u256()?; - backend.block_hash(block_number)? + backend.block_hash(block_number).await? }; self.stack.push_array(&block_hash)?; @@ -627,14 +673,16 @@ impl Machine { /// address of the current block's miner /// NOT SUPPORTED - pub fn opcode_coinbase(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_coinbase(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) } /// current block's Unix timestamp in seconds - pub fn opcode_timestamp(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_timestamp(&mut self, backend: &mut B) -> Result { let timestamp = backend.block_timestamp()?; self.stack.push_u256(timestamp)?; @@ -643,7 +691,8 @@ impl Machine { } /// current block's number - pub fn opcode_number(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_number(&mut self, backend: &mut B) -> Result { let block_number = backend.block_number()?; self.stack.push_u256(block_number)?; @@ -653,7 +702,8 @@ impl Machine { /// current block's difficulty /// NOT SUPPORTED - pub fn opcode_difficulty(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_difficulty(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) @@ -661,14 +711,16 @@ impl Machine { /// current block's gas limit /// NOT SUPPORTED - pub fn opcode_gaslimit(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gaslimit(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(U256::MAX)?; Ok(Action::Continue) } /// Istanbul hardfork, EIP-1344: current network's chain id - pub fn opcode_chainid(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_chainid(&mut self, backend: &mut B) -> Result { let chain_id = backend.chain_id(); self.stack.push_u256(chain_id)?; @@ -677,8 +729,9 @@ impl Machine { } /// Istanbul hardfork, EIP-1884: balance of the executing contract in wei - pub fn opcode_selfbalance(&mut self, backend: &mut B) -> Result { - let balance = backend.balance(&self.context.contract)?; + #[maybe_async] + pub async fn opcode_selfbalance(&mut self, backend: &mut B) -> Result { + let balance = backend.balance(&self.context.contract).await?; self.stack.push_u256(balance)?; @@ -687,21 +740,24 @@ impl Machine { /// London hardfork, EIP-3198: current block's base fee /// NOT SUPPORTED - pub fn opcode_basefee(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_basefee(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) } /// pops a (u)int256 off the stack and discards it - pub fn opcode_pop(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_pop(&mut self, _backend: &mut B) -> Result { self.stack.discard()?; Ok(Action::Continue) } /// reads a (u)int256 from memory - pub fn opcode_mload(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mload(&mut self, _backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let value = self.memory.read_32(offset)?; @@ -711,7 +767,8 @@ impl Machine { } /// writes a (u)int256 to memory - pub fn opcode_mstore(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mstore(&mut self, _backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let value = self.stack.pop_array()?; @@ -721,7 +778,8 @@ impl Machine { } /// writes a uint8 to memory - pub fn opcode_mstore8(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mstore8(&mut self, _backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let value = self.stack.pop_array()?; @@ -731,9 +789,10 @@ impl Machine { } /// reads a (u)int256 from storage - pub fn opcode_sload(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sload(&mut self, backend: &mut B) -> Result { let index = self.stack.pop_u256()?; - let value = backend.storage(&self.context.contract, &index)?; + let value = backend.storage(&self.context.contract, &index).await?; tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); @@ -743,7 +802,8 @@ impl Machine { } /// writes a (u)int256 to storage - pub fn opcode_sstore(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sstore(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -760,7 +820,8 @@ impl Machine { } /// unconditional jump - pub fn opcode_jump(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_jump(&mut self, _backend: &mut B) -> Result { const JUMPDEST: u8 = 0x5B; let value = self.stack.pop_usize()?; @@ -773,7 +834,8 @@ impl Machine { } /// conditional jump - pub fn opcode_jumpi(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_jumpi(&mut self, _backend: &mut B) -> Result { const JUMPDEST: u8 = 0x5B; let value = self.stack.pop_usize()?; @@ -791,33 +853,38 @@ impl Machine { } /// program counter - pub fn opcode_pc(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_pc(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.pc)?; Ok(Action::Continue) } /// memory size - pub fn opcode_msize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_msize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.memory.size())?; Ok(Action::Continue) } /// remaining gas - pub fn opcode_gas(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gas(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(self.gas_limit)?; Ok(Action::Continue) } /// metadata to annotate possible jump destinations - pub fn opcode_jumpdest(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_jumpdest(&mut self, _backend: &mut B) -> Result { Ok(Action::Continue) } /// Place zero on stack - pub fn opcode_push_0(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_0(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) @@ -825,7 +892,8 @@ impl Machine { /// Place 1 byte item on stack /// ~50% of contract bytecode are PUSH opcodes - pub fn opcode_push_1(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_1(&mut self, _backend: &mut B) -> Result { if self.execution_code.len() <= self.pc + 1 { return Err(Error::PushOutOfBounds(self.context.contract)); } @@ -838,7 +906,8 @@ impl Machine { } /// Place 2-31 byte item on stack. - pub fn opcode_push_2_31(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_2_31(&mut self, _backend: &mut B) -> Result { if self.execution_code.len() <= self.pc + 1 + N { return Err(Error::PushOutOfBounds(self.context.contract)); } @@ -854,7 +923,8 @@ impl Machine { } /// Place 32 byte item on stack - pub fn opcode_push_32(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_32(&mut self, _backend: &mut B) -> Result { if self.execution_code.len() <= self.pc + 1 + 32 { return Err(Error::PushOutOfBounds(self.context.contract)); } @@ -871,14 +941,16 @@ impl Machine { /// Duplicate Nth stack item /// ~25% of contract bytecode are DUP and SWAP opcodes - pub fn opcode_dup_1_16(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_dup_1_16(&mut self, _backend: &mut B) -> Result { self.stack.dup_1_16::()?; Ok(Action::Continue) } /// Exchange 1st and (N+1)th stack item - pub fn opcode_swap_1_16(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_swap_1_16(&mut self, _backend: &mut B) -> Result { self.stack.swap_1_16::()?; Ok(Action::Continue) @@ -886,7 +958,8 @@ impl Machine { /// Append log record with N topics #[rustfmt::skip] - pub fn opcode_log_0_4(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_log_0_4(&mut self, _backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -919,7 +992,8 @@ impl Machine { } /// Create a new account with associated code. - pub fn opcode_create(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_create(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -929,15 +1003,17 @@ impl Machine { let length = self.stack.pop_usize()?; let created_address = { - let nonce = backend.nonce(&self.context.contract)?; + let nonce = backend.nonce(&self.context.contract).await?; Address::from_create(&self.context.contract, nonce) }; self.opcode_create_impl(created_address, value, offset, length, backend) + .await } /// Constantinople harfork, EIP-1014: creates a create a new account with a deterministic address - pub fn opcode_create2(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_create2(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -953,9 +1029,11 @@ impl Machine { }; self.opcode_create_impl(created_address, value, offset, length, backend) + .await } - fn opcode_create_impl( + #[maybe_async] + async fn opcode_create_impl( &mut self, address: Address, value: U256, @@ -963,7 +1041,7 @@ impl Machine { length: usize, backend: &mut B, ) -> Result { - if backend.nonce(&self.context.contract)? == u64::MAX { + if backend.nonce(&self.context.contract).await? == u64::MAX { return Err(Error::NonceOverflow(self.context.contract)); } @@ -994,22 +1072,25 @@ impl Machine { sol_log_data(&[b"ENTER", b"CREATE", address.as_bytes()]); - if (backend.nonce(&address)? != 0) || (backend.code_size(&address)? != 0) { + if (backend.nonce(&address).await? != 0) || (backend.code_size(&address).await? != 0) { return Err(Error::DeployToExistingAccount(address, self.context.caller)); } - if backend.balance(&self.context.caller)? < value { + if backend.balance(&self.context.caller).await? < value { return Err(Error::InsufficientBalance(self.context.caller, value)); } backend.increment_nonce(address)?; - backend.transfer(self.context.caller, address, value)?; + backend + .transfer(self.context.caller, address, value) + .await?; Ok(Action::Noop) } /// Message-call into an account - pub fn opcode_call(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_call(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let value = self.stack.pop_u256()?; @@ -1022,7 +1103,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { caller: self.context.contract, @@ -1048,17 +1129,20 @@ impl Machine { return Err(Error::StaticModeViolation(self.context.caller)); } - if backend.balance(&self.context.caller)? < value { + if backend.balance(&self.context.caller).await? < value { return Err(Error::InsufficientBalance(self.context.caller, value)); } - backend.transfer(self.context.caller, self.context.contract, value)?; + backend + .transfer(self.context.caller, self.context.contract, value) + .await?; - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Message-call into this account with an alternative account’s code - pub fn opcode_callcode(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_callcode(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let value = self.stack.pop_u256()?; @@ -1071,7 +1155,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { caller: self.context.contract, @@ -1093,16 +1177,17 @@ impl Machine { sol_log_data(&[b"ENTER", b"CALLCODE", address.as_bytes()]); - if backend.balance(&self.context.caller)? < value { + if backend.balance(&self.context.caller).await? < value { return Err(Error::InsufficientBalance(self.context.caller, value)); } - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Homestead hardfork, EIP-7: Message-call into this account with an alternative account’s code, /// but persisting the current values for sender and value - pub fn opcode_delegatecall(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_delegatecall(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let args_offset = self.stack.pop_usize()?; @@ -1114,7 +1199,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { code_address: Some(address), @@ -1134,12 +1219,13 @@ impl Machine { sol_log_data(&[b"ENTER", b"DELEGATECALL", address.as_bytes()]); - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Byzantium hardfork, EIP-214: Static message-call into an account /// Disallowed contract creation, event emission, storage modification and contract destruction - pub fn opcode_staticcall(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_staticcall(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let args_offset = self.stack.pop_usize()?; @@ -1151,7 +1237,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { caller: self.context.contract, @@ -1175,40 +1261,49 @@ impl Machine { sol_log_data(&[b"ENTER", b"STATICCALL", address.as_bytes()]); - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Call precompile contract. /// Returns `Action::Noop` if address is not a precompile - fn opcode_call_precompile_impl( + #[maybe_async] + async fn opcode_call_precompile_impl( &mut self, backend: &mut B, address: &Address, ) -> Result { - let result = Self::precompile(address, &self.call_data).map(Ok); - let result = result.or_else(|| { - backend.precompile_extension(&self.context, address, &self.call_data, self.is_static) - }); + let result = match Self::precompile(address, &self.call_data).map(Ok) { + Some(x) => Some(x), + None => { + backend + .precompile_extension(&self.context, address, &self.call_data, self.is_static) + .await + } + }; if let Some(return_data) = result.transpose()? { - return self.opcode_return_impl(Buffer::from_slice(&return_data), backend); + return self + .opcode_return_impl(Buffer::from_slice(&return_data), backend) + .await; } Ok(Action::Noop) } /// Halt execution returning output data - pub fn opcode_return(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_return(&mut self, backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; let return_data = self.memory.read_buffer(offset, length)?; - self.opcode_return_impl(return_data, backend) + self.opcode_return_impl(return_data, backend).await } /// Halt execution returning output data - pub fn opcode_return_impl( + #[maybe_async] + pub async fn opcode_return_impl( &mut self, mut return_data: Buffer, backend: &mut B, @@ -1251,16 +1346,22 @@ impl Machine { } /// Byzantium hardfork, EIP-140: Halt execution reverting state changes but returning data - pub fn opcode_revert(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_revert(&mut self, backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; let return_data = self.memory.read_buffer(offset, length)?; - self.opcode_revert_impl(return_data, backend) + self.opcode_revert_impl(return_data, backend).await } - pub fn opcode_revert_impl(&mut self, return_data: Buffer, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_revert_impl( + &mut self, + return_data: Buffer, + backend: &mut B, + ) -> Result { backend.revert_snapshot(); sol_log_data(&[b"EXIT", b"REVERT", &return_data]); @@ -1293,7 +1394,8 @@ impl Machine { } /// Invalid instruction - pub fn opcode_invalid(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_invalid(&mut self, _backend: &mut B) -> Result { Err(Error::InvalidOpcode( self.context.contract, self.execution_code[self.pc], @@ -1301,15 +1403,18 @@ impl Machine { } /// Halt execution, destroys the contract and send all funds to address - pub fn opcode_selfdestruct(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_selfdestruct(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } let address = *self.stack.pop_address()?; - let value = backend.balance(&self.context.contract)?; - backend.transfer(self.context.contract, address, value)?; + let value = backend.balance(&self.context.contract).await?; + backend + .transfer(self.context.contract, address, value) + .await?; backend.selfdestruct(self.context.contract)?; backend.commit_snapshot(); @@ -1342,7 +1447,8 @@ impl Machine { } /// Halts execution of the contract - pub fn opcode_stop(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_stop(&mut self, backend: &mut B) -> Result { backend.commit_snapshot(); sol_log_data(&[b"EXIT", b"STOP"]); diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index 086a8e3a1..cc169efc2 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -1,173 +1,205 @@ -#![allow(clippy::type_complexity)] - use crate::error::Result; use super::{database::Database, opcode::Action, Machine}; -type OpCode = (&'static str, fn(&mut Machine, &mut B) -> Result); - -impl Machine { - const OPCODE_UNKNOWN: OpCode = ("", Self::opcode_unknown); - pub const OPCODES: [OpCode; 256] = { - let mut opcodes: [OpCode; 256] = [Self::OPCODE_UNKNOWN; 256]; - - opcodes[0x00] = ("STOP", Self::opcode_stop); - opcodes[0x01] = ("ADD", Self::opcode_add); - opcodes[0x02] = ("MUL", Self::opcode_mul); - opcodes[0x03] = ("SUB", Self::opcode_sub); - opcodes[0x04] = ("DIV", Self::opcode_div); - opcodes[0x05] = ("SDIV", Self::opcode_sdiv); - opcodes[0x06] = ("MOD", Self::opcode_mod); - opcodes[0x07] = ("SMOD", Self::opcode_smod); - opcodes[0x08] = ("ADDMOD", Self::opcode_addmod); - opcodes[0x09] = ("MULMOD", Self::opcode_mulmod); - opcodes[0x0A] = ("EXP", Self::opcode_exp); - opcodes[0x0B] = ("SIGNEXTEND", Self::opcode_signextend); - - opcodes[0x10] = ("LT", Self::opcode_lt); - opcodes[0x11] = ("GT", Self::opcode_gt); - opcodes[0x12] = ("SLT", Self::opcode_slt); - opcodes[0x13] = ("SGT", Self::opcode_sgt); - opcodes[0x14] = ("EQ", Self::opcode_eq); - opcodes[0x15] = ("ISZERO", Self::opcode_iszero); - opcodes[0x16] = ("AND", Self::opcode_and); - opcodes[0x17] = ("OR", Self::opcode_or); - opcodes[0x18] = ("XOR", Self::opcode_xor); - opcodes[0x19] = ("NOT", Self::opcode_not); - opcodes[0x1A] = ("BYTE", Self::opcode_byte); - opcodes[0x1B] = ("SHL", Self::opcode_shl); - opcodes[0x1C] = ("SHR", Self::opcode_shr); - opcodes[0x1D] = ("SAR", Self::opcode_sar); - - opcodes[0x20] = ("KECCAK256", Self::opcode_sha3); - - opcodes[0x30] = ("ADDRESS", Self::opcode_address); - opcodes[0x31] = ("BALANCE", Self::opcode_balance); - opcodes[0x32] = ("ORIGIN", Self::opcode_origin); - opcodes[0x33] = ("CALLER", Self::opcode_caller); - opcodes[0x34] = ("CALLVALUE", Self::opcode_callvalue); - opcodes[0x35] = ("CALLDATALOAD", Self::opcode_calldataload); - opcodes[0x36] = ("CALLDATASIZE", Self::opcode_calldatasize); - opcodes[0x37] = ("CALLDATACOPY", Self::opcode_calldatacopy); - opcodes[0x38] = ("CODESIZE", Self::opcode_codesize); - opcodes[0x39] = ("CODECOPY", Self::opcode_codecopy); - opcodes[0x3A] = ("GASPRICE", Self::opcode_gasprice); - opcodes[0x3B] = ("EXTCODESIZE", Self::opcode_extcodesize); - opcodes[0x3C] = ("EXTCODECOPY", Self::opcode_extcodecopy); - opcodes[0x3D] = ("RETURNDATASIZE", Self::opcode_returndatasize); - opcodes[0x3E] = ("RETURNDATACOPY", Self::opcode_returndatacopy); - opcodes[0x3F] = ("EXTCODEHASH", Self::opcode_extcodehash); - opcodes[0x40] = ("BLOCKHASH", Self::opcode_blockhash); - opcodes[0x41] = ("COINBASE", Self::opcode_coinbase); - opcodes[0x42] = ("TIMESTAMP", Self::opcode_timestamp); - opcodes[0x43] = ("NUMBER", Self::opcode_number); - opcodes[0x44] = ("PREVRANDAO", Self::opcode_difficulty); - opcodes[0x45] = ("GASLIMIT", Self::opcode_gaslimit); - opcodes[0x46] = ("CHAINID", Self::opcode_chainid); - opcodes[0x47] = ("SELFBALANCE", Self::opcode_selfbalance); - opcodes[0x48] = ("BASEFEE", Self::opcode_basefee); - - opcodes[0x50] = ("POP", Self::opcode_pop); - opcodes[0x51] = ("MLOAD", Self::opcode_mload); - opcodes[0x52] = ("MSTORE", Self::opcode_mstore); - opcodes[0x53] = ("MSTORE8", Self::opcode_mstore8); - opcodes[0x54] = ("SLOAD", Self::opcode_sload); - opcodes[0x55] = ("SSTORE", Self::opcode_sstore); - opcodes[0x56] = ("JUMP", Self::opcode_jump); - opcodes[0x57] = ("JUMPI", Self::opcode_jumpi); - opcodes[0x58] = ("PC", Self::opcode_pc); - opcodes[0x59] = ("MSIZE", Self::opcode_msize); - opcodes[0x5A] = ("GAS", Self::opcode_gas); - opcodes[0x5B] = ("JUMPDEST", Self::opcode_jumpdest); - - opcodes[0x5F] = ("PUSH0", Self::opcode_push_0); - opcodes[0x60] = ("PUSH1", Self::opcode_push_1); - opcodes[0x61] = ("PUSH2", Self::opcode_push_2_31::<2>); - opcodes[0x62] = ("PUSH3", Self::opcode_push_2_31::<3>); - opcodes[0x63] = ("PUSH4", Self::opcode_push_2_31::<4>); - opcodes[0x64] = ("PUSH5", Self::opcode_push_2_31::<5>); - opcodes[0x65] = ("PUSH6", Self::opcode_push_2_31::<6>); - opcodes[0x66] = ("PUSH7", Self::opcode_push_2_31::<7>); - opcodes[0x67] = ("PUSH8", Self::opcode_push_2_31::<8>); - opcodes[0x68] = ("PUSH9", Self::opcode_push_2_31::<9>); - opcodes[0x69] = ("PUSH10", Self::opcode_push_2_31::<10>); - opcodes[0x6A] = ("PUSH11", Self::opcode_push_2_31::<11>); - opcodes[0x6B] = ("PUSH12", Self::opcode_push_2_31::<12>); - opcodes[0x6C] = ("PUSH13", Self::opcode_push_2_31::<13>); - opcodes[0x6D] = ("PUSH14", Self::opcode_push_2_31::<14>); - opcodes[0x6E] = ("PUSH15", Self::opcode_push_2_31::<15>); - opcodes[0x6F] = ("PUSH16", Self::opcode_push_2_31::<16>); - opcodes[0x70] = ("PUSH17", Self::opcode_push_2_31::<17>); - opcodes[0x71] = ("PUSH18", Self::opcode_push_2_31::<18>); - opcodes[0x72] = ("PUSH19", Self::opcode_push_2_31::<19>); - opcodes[0x73] = ("PUSH20", Self::opcode_push_2_31::<20>); - opcodes[0x74] = ("PUSH21", Self::opcode_push_2_31::<21>); - opcodes[0x75] = ("PUSH22", Self::opcode_push_2_31::<22>); - opcodes[0x76] = ("PUSH23", Self::opcode_push_2_31::<23>); - opcodes[0x77] = ("PUSH24", Self::opcode_push_2_31::<24>); - opcodes[0x78] = ("PUSH25", Self::opcode_push_2_31::<25>); - opcodes[0x79] = ("PUSH26", Self::opcode_push_2_31::<26>); - opcodes[0x7A] = ("PUSH27", Self::opcode_push_2_31::<27>); - opcodes[0x7B] = ("PUSH28", Self::opcode_push_2_31::<28>); - opcodes[0x7C] = ("PUSH29", Self::opcode_push_2_31::<29>); - opcodes[0x7D] = ("PUSH30", Self::opcode_push_2_31::<30>); - opcodes[0x7E] = ("PUSH31", Self::opcode_push_2_31::<31>); - opcodes[0x7F] = ("PUSH32", Self::opcode_push_32); - - opcodes[0x80] = ("DUP1", Self::opcode_dup_1_16::<1>); - opcodes[0x81] = ("DUP2", Self::opcode_dup_1_16::<2>); - opcodes[0x82] = ("DUP3", Self::opcode_dup_1_16::<3>); - opcodes[0x83] = ("DUP4", Self::opcode_dup_1_16::<4>); - opcodes[0x84] = ("DUP5", Self::opcode_dup_1_16::<5>); - opcodes[0x85] = ("DUP6", Self::opcode_dup_1_16::<6>); - opcodes[0x86] = ("DUP7", Self::opcode_dup_1_16::<7>); - opcodes[0x87] = ("DUP8", Self::opcode_dup_1_16::<8>); - opcodes[0x88] = ("DUP9", Self::opcode_dup_1_16::<9>); - opcodes[0x89] = ("DUP10", Self::opcode_dup_1_16::<10>); - opcodes[0x8A] = ("DUP11", Self::opcode_dup_1_16::<11>); - opcodes[0x8B] = ("DUP12", Self::opcode_dup_1_16::<12>); - opcodes[0x8C] = ("DUP13", Self::opcode_dup_1_16::<13>); - opcodes[0x8D] = ("DUP14", Self::opcode_dup_1_16::<14>); - opcodes[0x8E] = ("DUP15", Self::opcode_dup_1_16::<15>); - opcodes[0x8F] = ("DUP16", Self::opcode_dup_1_16::<16>); - - opcodes[0x90] = ("SWAP1", Self::opcode_swap_1_16::<1>); - opcodes[0x91] = ("SWAP2", Self::opcode_swap_1_16::<2>); - opcodes[0x92] = ("SWAP3", Self::opcode_swap_1_16::<3>); - opcodes[0x93] = ("SWAP4", Self::opcode_swap_1_16::<4>); - opcodes[0x94] = ("SWAP5", Self::opcode_swap_1_16::<5>); - opcodes[0x95] = ("SWAP6", Self::opcode_swap_1_16::<6>); - opcodes[0x96] = ("SWAP7", Self::opcode_swap_1_16::<7>); - opcodes[0x97] = ("SWAP8", Self::opcode_swap_1_16::<8>); - opcodes[0x98] = ("SWAP9", Self::opcode_swap_1_16::<9>); - opcodes[0x99] = ("SWAP10", Self::opcode_swap_1_16::<10>); - opcodes[0x9A] = ("SWAP11", Self::opcode_swap_1_16::<11>); - opcodes[0x9B] = ("SWAP12", Self::opcode_swap_1_16::<12>); - opcodes[0x9C] = ("SWAP13", Self::opcode_swap_1_16::<13>); - opcodes[0x9D] = ("SWAP14", Self::opcode_swap_1_16::<14>); - opcodes[0x9E] = ("SWAP15", Self::opcode_swap_1_16::<15>); - opcodes[0x9F] = ("SWAP16", Self::opcode_swap_1_16::<16>); - - opcodes[0xA0] = ("LOG0", Self::opcode_log_0_4::<0>); - opcodes[0xA1] = ("LOG1", Self::opcode_log_0_4::<1>); - opcodes[0xA2] = ("LOG2", Self::opcode_log_0_4::<2>); - opcodes[0xA3] = ("LOG3", Self::opcode_log_0_4::<3>); - opcodes[0xA4] = ("LOG4", Self::opcode_log_0_4::<4>); - - opcodes[0xF0] = ("CREATE", Self::opcode_create); - opcodes[0xF1] = ("CALL", Self::opcode_call); - opcodes[0xF2] = ("CALLCODE", Self::opcode_callcode); - opcodes[0xF3] = ("RETURN", Self::opcode_return); - opcodes[0xF4] = ("DELEGATECALL", Self::opcode_delegatecall); - opcodes[0xF5] = ("CREATE2", Self::opcode_create2); - - opcodes[0xFA] = ("STATICCALL", Self::opcode_staticcall); - - opcodes[0xFD] = ("REVERT", Self::opcode_revert); - opcodes[0xFE] = ("INVALID", Self::opcode_invalid); - - opcodes[0xFF] = ("SELFDESTRUCT", Self::opcode_selfdestruct); - - opcodes - }; +macro_rules! opcode_table { + ($( $opcode:literal, $opname:literal, $op:path;)*) => { + #[cfg(target_os = "solana")] + type OpCode = fn(&mut Machine, &mut B) -> Result; + + #[cfg(target_os = "solana")] + impl Machine { + const OPCODES: [OpCode; 256] = { + let mut opcodes: [OpCode; 256] = [Self::opcode_unknown; 256]; + + $(opcodes[$opcode as usize] = $op;)* + + opcodes + }; + + pub fn execute_opcode(&mut self, backend: &mut B, opcode: u8) -> Result { + // SAFETY: OPCODES.len() == 256, opcode <= 255 + let opcode_fn = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; + opcode_fn(self, backend) + } + } + + #[cfg(not(target_os = "solana"))] + impl Machine { + pub async fn execute_opcode(&mut self, backend: &mut B, opcode: u8) -> Result { + match opcode { + $($opcode => $op(self, backend).await,)* + _ => Self::opcode_unknown(self, backend).await, + } + } + } + + #[cfg(not(target_os = "solana"))] + pub const OPNAMES: [&str; 256] = { + let mut opnames: [&str; 256] = [""; 256]; + + $(opnames[$opcode as usize] = $opname;)* + + opnames + }; + } } + +opcode_table![ + 0x00, "STOP", Self::opcode_stop; + 0x01, "ADD", Self::opcode_add; + 0x02, "MUL", Self::opcode_mul; + 0x03, "SUB", Self::opcode_sub; + 0x04, "DIV", Self::opcode_div; + 0x05, "SDIV", Self::opcode_sdiv; + 0x06, "MOD", Self::opcode_mod; + 0x07, "SMOD", Self::opcode_smod; + 0x08, "ADDMOD", Self::opcode_addmod; + 0x09, "MULMOD", Self::opcode_mulmod; + 0x0A, "EXP", Self::opcode_exp; + 0x0B, "SIGNEXTEND", Self::opcode_signextend; + + 0x10, "LT", Self::opcode_lt; + 0x11, "GT", Self::opcode_gt; + 0x12, "SLT", Self::opcode_slt; + 0x13, "SGT", Self::opcode_sgt; + 0x14, "EQ", Self::opcode_eq; + 0x15, "ISZERO", Self::opcode_iszero; + 0x16, "AND", Self::opcode_and; + 0x17, "OR", Self::opcode_or; + 0x18, "XOR", Self::opcode_xor; + 0x19, "NOT", Self::opcode_not; + 0x1A, "BYTE", Self::opcode_byte; + 0x1B, "SHL", Self::opcode_shl; + 0x1C, "SHR", Self::opcode_shr; + 0x1D, "SAR", Self::opcode_sar; + + 0x20, "KECCAK256", Self::opcode_sha3; + + 0x30, "ADDRESS", Self::opcode_address; + 0x31, "BALANCE", Self::opcode_balance; + 0x32, "ORIGIN", Self::opcode_origin; + 0x33, "CALLER", Self::opcode_caller; + 0x34, "CALLVALUE", Self::opcode_callvalue; + 0x35, "CALLDATALOAD", Self::opcode_calldataload; + 0x36, "CALLDATASIZE", Self::opcode_calldatasize; + 0x37, "CALLDATACOPY", Self::opcode_calldatacopy; + 0x38, "CODESIZE", Self::opcode_codesize; + 0x39, "CODECOPY", Self::opcode_codecopy; + 0x3A, "GASPRICE", Self::opcode_gasprice; + 0x3B, "EXTCODESIZE", Self::opcode_extcodesize; + 0x3C, "EXTCODECOPY", Self::opcode_extcodecopy; + 0x3D, "RETURNDATASIZE", Self::opcode_returndatasize; + 0x3E, "RETURNDATACOPY", Self::opcode_returndatacopy; + 0x3F, "EXTCODEHASH", Self::opcode_extcodehash; + 0x40, "BLOCKHASH", Self::opcode_blockhash; + 0x41, "COINBASE", Self::opcode_coinbase; + 0x42, "TIMESTAMP", Self::opcode_timestamp; + 0x43, "NUMBER", Self::opcode_number; + 0x44, "PREVRANDAO", Self::opcode_difficulty; + 0x45, "GASLIMIT", Self::opcode_gaslimit; + 0x46, "CHAINID", Self::opcode_chainid; + 0x47, "SELFBALANCE", Self::opcode_selfbalance; + 0x48, "BASEFEE", Self::opcode_basefee; + + 0x50, "POP", Self::opcode_pop; + 0x51, "MLOAD", Self::opcode_mload; + 0x52, "MSTORE", Self::opcode_mstore; + 0x53, "MSTORE8", Self::opcode_mstore8; + 0x54, "SLOAD", Self::opcode_sload; + 0x55, "SSTORE", Self::opcode_sstore; + 0x56, "JUMP", Self::opcode_jump; + 0x57, "JUMPI", Self::opcode_jumpi; + 0x58, "PC", Self::opcode_pc; + 0x59, "MSIZE", Self::opcode_msize; + 0x5A, "GAS", Self::opcode_gas; + 0x5B, "JUMPDEST", Self::opcode_jumpdest; + + 0x5F, "PUSH0", Self::opcode_push_0; + 0x60, "PUSH1", Self::opcode_push_1; + 0x61, "PUSH2", Self::opcode_push_2_31::<2>; + 0x62, "PUSH3", Self::opcode_push_2_31::<3>; + 0x63, "PUSH4", Self::opcode_push_2_31::<4>; + 0x64, "PUSH5", Self::opcode_push_2_31::<5>; + 0x65, "PUSH6", Self::opcode_push_2_31::<6>; + 0x66, "PUSH7", Self::opcode_push_2_31::<7>; + 0x67, "PUSH8", Self::opcode_push_2_31::<8>; + 0x68, "PUSH9", Self::opcode_push_2_31::<9>; + 0x69, "PUSH10", Self::opcode_push_2_31::<10>; + 0x6A, "PUSH11", Self::opcode_push_2_31::<11>; + 0x6B, "PUSH12", Self::opcode_push_2_31::<12>; + 0x6C, "PUSH13", Self::opcode_push_2_31::<13>; + 0x6D, "PUSH14", Self::opcode_push_2_31::<14>; + 0x6E, "PUSH15", Self::opcode_push_2_31::<15>; + 0x6F, "PUSH16", Self::opcode_push_2_31::<16>; + 0x70, "PUSH17", Self::opcode_push_2_31::<17>; + 0x71, "PUSH18", Self::opcode_push_2_31::<18>; + 0x72, "PUSH19", Self::opcode_push_2_31::<19>; + 0x73, "PUSH20", Self::opcode_push_2_31::<20>; + 0x74, "PUSH21", Self::opcode_push_2_31::<21>; + 0x75, "PUSH22", Self::opcode_push_2_31::<22>; + 0x76, "PUSH23", Self::opcode_push_2_31::<23>; + 0x77, "PUSH24", Self::opcode_push_2_31::<24>; + 0x78, "PUSH25", Self::opcode_push_2_31::<25>; + 0x79, "PUSH26", Self::opcode_push_2_31::<26>; + 0x7A, "PUSH27", Self::opcode_push_2_31::<27>; + 0x7B, "PUSH28", Self::opcode_push_2_31::<28>; + 0x7C, "PUSH29", Self::opcode_push_2_31::<29>; + 0x7D, "PUSH30", Self::opcode_push_2_31::<30>; + 0x7E, "PUSH31", Self::opcode_push_2_31::<31>; + 0x7F, "PUSH32", Self::opcode_push_32; + + 0x80, "DUP1", Self::opcode_dup_1_16::<1>; + 0x81, "DUP2", Self::opcode_dup_1_16::<2>; + 0x82, "DUP3", Self::opcode_dup_1_16::<3>; + 0x83, "DUP4", Self::opcode_dup_1_16::<4>; + 0x84, "DUP5", Self::opcode_dup_1_16::<5>; + 0x85, "DUP6", Self::opcode_dup_1_16::<6>; + 0x86, "DUP7", Self::opcode_dup_1_16::<7>; + 0x87, "DUP8", Self::opcode_dup_1_16::<8>; + 0x88, "DUP9", Self::opcode_dup_1_16::<9>; + 0x89, "DUP10", Self::opcode_dup_1_16::<10>; + 0x8A, "DUP11", Self::opcode_dup_1_16::<11>; + 0x8B, "DUP12", Self::opcode_dup_1_16::<12>; + 0x8C, "DUP13", Self::opcode_dup_1_16::<13>; + 0x8D, "DUP14", Self::opcode_dup_1_16::<14>; + 0x8E, "DUP15", Self::opcode_dup_1_16::<15>; + 0x8F, "DUP16", Self::opcode_dup_1_16::<16>; + + 0x90, "SWAP1", Self::opcode_swap_1_16::<1>; + 0x91, "SWAP2", Self::opcode_swap_1_16::<2>; + 0x92, "SWAP3", Self::opcode_swap_1_16::<3>; + 0x93, "SWAP4", Self::opcode_swap_1_16::<4>; + 0x94, "SWAP5", Self::opcode_swap_1_16::<5>; + 0x95, "SWAP6", Self::opcode_swap_1_16::<6>; + 0x96, "SWAP7", Self::opcode_swap_1_16::<7>; + 0x97, "SWAP8", Self::opcode_swap_1_16::<8>; + 0x98, "SWAP9", Self::opcode_swap_1_16::<9>; + 0x99, "SWAP10", Self::opcode_swap_1_16::<10>; + 0x9A, "SWAP11", Self::opcode_swap_1_16::<11>; + 0x9B, "SWAP12", Self::opcode_swap_1_16::<12>; + 0x9C, "SWAP13", Self::opcode_swap_1_16::<13>; + 0x9D, "SWAP14", Self::opcode_swap_1_16::<14>; + 0x9E, "SWAP15", Self::opcode_swap_1_16::<15>; + 0x9F, "SWAP16", Self::opcode_swap_1_16::<16>; + + 0xA0, "LOG0", Self::opcode_log_0_4::<0>; + 0xA1, "LOG1", Self::opcode_log_0_4::<1>; + 0xA2, "LOG2", Self::opcode_log_0_4::<2>; + 0xA3, "LOG3", Self::opcode_log_0_4::<3>; + 0xA4, "LOG4", Self::opcode_log_0_4::<4>; + + 0xF0, "CREATE", Self::opcode_create; + 0xF1, "CALL", Self::opcode_call; + 0xF2, "CALLCODE", Self::opcode_callcode; + 0xF3, "RETURN", Self::opcode_return; + 0xF4, "DELEGATECALL", Self::opcode_delegatecall; + 0xF5, "CREATE2", Self::opcode_create2; + + 0xFA, "STATICCALL", Self::opcode_staticcall; + + 0xFD, "REVERT", Self::opcode_revert; + 0xFE, "INVALID", Self::opcode_invalid; + + 0xFF, "SELFDESTRUCT", Self::opcode_selfdestruct; +]; diff --git a/evm_loader/program/src/evm/precompile/ecrecover.rs b/evm_loader/program/src/evm/precompile/ecrecover.rs index c45186e20..425d074b0 100644 --- a/evm_loader/program/src/evm/precompile/ecrecover.rs +++ b/evm_loader/program/src/evm/precompile/ecrecover.rs @@ -3,6 +3,7 @@ use ethnum::U256; use solana_program::keccak; use solana_program::secp256k1_recover::secp256k1_recover; +#[allow(clippy::manual_let_else)] #[must_use] pub fn ecrecover(input: &[u8]) -> Vec { debug_print!("ecrecover"); diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index 8b7eb2af1..9470e0fd0 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -7,8 +7,8 @@ use std::{ use ethnum::{I256, U256}; -#[cfg(feature = "tracing")] -use crate::evm::tracing::TracerTypeOpt; +#[cfg(not(target_os = "solana"))] +use crate::evm::TracerTypeOpt; use crate::{error::Error, types::Address}; use super::tracing_event; @@ -20,12 +20,12 @@ pub struct Stack { begin: *mut u8, end: *mut u8, top: *mut u8, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, } impl Stack { - pub fn new(#[cfg(feature = "tracing")] tracer: TracerTypeOpt) -> Self { + pub fn new(#[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt) -> Self { let (begin, end) = unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); let begin = crate::allocator::EVM.alloc(layout); @@ -42,12 +42,12 @@ impl Stack { begin, end, top: begin, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, } } - #[allow(dead_code)] + #[cfg(not(target_os = "solana"))] pub fn to_vec(&self) -> Vec<[u8; 32]> { let slice = unsafe { let start = self.begin.cast::<[u8; 32]>(); @@ -316,7 +316,7 @@ impl<'de> serde::Deserialize<'de> for Stack { } let mut stack = Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] None, ); unsafe { diff --git a/evm_loader/program/src/evm/tracing/mod.rs b/evm_loader/program/src/evm/tracing/mod.rs index 024e7d3ed..b30817cb7 100644 --- a/evm_loader/program/src/evm/tracing/mod.rs +++ b/evm_loader/program/src/evm/tracing/mod.rs @@ -1,6 +1,7 @@ +use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; -use std::sync::{Arc, RwLock}; +use std::rc::Rc; use crate::account::EthereumAccount; use crate::executor::Action; @@ -26,7 +27,7 @@ pub trait EventListener: Send + Sync + Debug { fn into_traces(self: Box, emulation_result: EmulationResult) -> Value; } -pub type TracerType = Arc>>; +pub type TracerType = Rc>>; pub type TracerTypeOpt = Option; /// Trace event diff --git a/evm_loader/program/src/evm/tracing/tracers/mod.rs b/evm_loader/program/src/evm/tracing/tracers/mod.rs index 3913a3061..ed98e1af9 100644 --- a/evm_loader/program/src/evm/tracing/tracers/mod.rs +++ b/evm_loader/program/src/evm/tracing/tracers/mod.rs @@ -1,12 +1,13 @@ use crate::evm::tracing::tracers::struct_logger::StructLogger; use crate::evm::tracing::TraceConfig; use crate::evm::tracing::TracerType; -use std::sync::{Arc, RwLock}; +use std::cell::RefCell; +use std::rc::Rc; pub mod struct_logger; pub fn new_tracer(trace_config: &TraceConfig) -> crate::error::Result { - Ok(Arc::new(RwLock::new( + Ok(Rc::new(RefCell::new( match trace_config.tracer.as_deref() { None | Some("") => Box::new(StructLogger::new(trace_config)), _ => { diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs index 6b5380e9b..08ebd2dc1 100644 --- a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs +++ b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs @@ -4,11 +4,9 @@ use ethnum::U256; use serde::Serialize; use serde_json::Value; -use crate::account_storage::ProgramAccountStorage; +use crate::evm::opcode_table::OPNAMES; use crate::evm::tracing::TraceConfig; use crate::evm::tracing::{EmulationResult, Event, EventListener}; -use crate::evm::Machine; -use crate::executor::ExecutorState; use crate::types::hexbytes::HexBytes; /// `StructLoggerResult` groups all structured logs emitted by the EVM @@ -68,7 +66,7 @@ impl StructLog { stack: Option>, storage: Option>, ) -> Self { - let (op, _) = Machine::>::OPCODES[opcode as usize]; + let op = OPNAMES[opcode as usize]; Self { pc, op, diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 45405f946..83af0d221 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -110,6 +110,7 @@ mod tests { let _deserialized: Action = bincode::deserialize(&serialized).unwrap(); } + #[cfg(not(target_os = "solana"))] #[test] fn roundtrip_json() { let action = Action::EvmSetStorage { diff --git a/evm_loader/program/src/executor/cache.rs b/evm_loader/program/src/executor/cache.rs index dbc8f5f09..062d2829a 100644 --- a/evm_loader/program/src/executor/cache.rs +++ b/evm_loader/program/src/executor/cache.rs @@ -1,11 +1,10 @@ +use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; + use ethnum::U256; use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; - -use crate::account_storage::AccountStorage; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Clone, Serialize, Deserialize)] pub struct OwnedAccountInfo { pub key: Pubkey, pub is_signer: bool, @@ -63,15 +62,3 @@ pub struct Cache { #[serde(with = "ethnum::serde::bytes::le")] pub block_timestamp: U256, } - -impl Cache { - pub fn get_account_or_insert( - &mut self, - key: Pubkey, - backend: &B, - ) -> &mut OwnedAccountInfo { - self.solana_accounts - .entry(key) - .or_insert_with(|| backend.clone_solana_account(&key)) - } -} diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index d0358dcd0..180cfed6d 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -3,6 +3,7 @@ use std::convert::{Into, TryInto}; use ethnum::U256; +use maybe_async::maybe_async; use mpl_token_metadata::state::{ Creator, Metadata, TokenMetadataAccount, TokenStandard, CREATE_FEE, MAX_MASTER_EDITION_LEN, MAX_METADATA_LEN, @@ -25,8 +26,9 @@ use crate::{ // "[0x69, 0x1f, 0x34, 0x31]": "name(bytes32)" // "[0x6b, 0xaa, 0x03, 0x30]": "symbol(bytes32)" -pub fn metaplex( - state: &mut ExecutorState, +#[maybe_async] +pub async fn metaplex( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -73,27 +75,27 @@ pub fn metaplex( [0xf7, 0xb6, 0x37, 0xbb] => { // "isInitialized(bytes32)" let mint = read_pubkey(input)?; - is_initialized(context, state, mint) + is_initialized(context, state, mint).await } [0x23, 0x5b, 0x2b, 0x94] => { // "isNFT(bytes32)" let mint = read_pubkey(input)?; - is_nft(context, state, mint) + is_nft(context, state, mint).await } [0x9e, 0xd1, 0x9d, 0xdb] => { // "uri(bytes32)" let mint = read_pubkey(input)?; - uri(context, state, mint) + uri(context, state, mint).await } [0x69, 0x1f, 0x34, 0x31] => { // "name(bytes32)" let mint = read_pubkey(input)?; - token_name(context, state, mint) + token_name(context, state, mint).await } [0x6b, 0xaa, 0x03, 0x30] => { // "symbol(bytes32)" let mint = read_pubkey(input)?; - symbol(context, state, mint) + symbol(context, state, mint).await } _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), } @@ -236,22 +238,26 @@ fn create_master_edition( Ok(edition_pubkey.to_bytes().to_vec()) } -fn is_initialized( +#[maybe_async] +async fn is_initialized( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let is_initialized = metadata(context, state, mint)?.map_or_else(|| false, |_| true); + let is_initialized = metadata(context, state, mint) + .await? + .map_or_else(|| false, |_| true); Ok(to_solidity_bool(is_initialized)) } -fn is_nft( +#[maybe_async] +async fn is_nft( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let is_nft = metadata(context, state, mint)?.map_or_else( + let is_nft = metadata(context, state, mint).await?.map_or_else( || false, |m| m.token_standard == Some(TokenStandard::NonFungible), ); @@ -259,43 +265,53 @@ fn is_nft( Ok(to_solidity_bool(is_nft)) } -fn uri( +#[maybe_async] +async fn uri( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let uri = metadata(context, state, mint)?.map_or_else(String::new, |m| m.data.uri); + let uri = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.data.uri); Ok(to_solidity_string(uri.trim_end_matches('\0'))) } -fn token_name( +#[maybe_async] +async fn token_name( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let token_name = metadata(context, state, mint)?.map_or_else(String::new, |m| m.data.name); + let token_name = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.data.name); Ok(to_solidity_string(token_name.trim_end_matches('\0'))) } -fn symbol( +#[maybe_async] +async fn symbol( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let symbol = metadata(context, state, mint)?.map_or_else(String::new, |m| m.data.symbol); + let symbol = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.data.symbol); Ok(to_solidity_string(symbol.trim_end_matches('\0'))) } -fn metadata( +#[maybe_async] +async fn metadata( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - let metadata_account = state.external_account(metadata_pubkey)?; + let metadata_account = state.external_account(metadata_pubkey).await?; let result = { if mpl_token_metadata::check_id(&metadata_account.owner) { diff --git a/evm_loader/program/src/executor/precompile_extension/mod.rs b/evm_loader/program/src/executor/precompile_extension/mod.rs index 06870b608..3936615b0 100644 --- a/evm_loader/program/src/executor/precompile_extension/mod.rs +++ b/evm_loader/program/src/executor/precompile_extension/mod.rs @@ -1,4 +1,5 @@ use crate::{account_storage::AccountStorage, error::Result, evm::Context, types::Address}; +use maybe_async::maybe_async; use super::ExecutorState; @@ -34,7 +35,8 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { || *address == Self::SYSTEM_ACCOUNT_METAPLEX } - pub fn call_precompile_extension( + #[maybe_async] + pub async fn call_precompile_extension( &mut self, context: &Context, address: &Address, @@ -42,17 +44,17 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { is_static: bool, ) -> Option>> { match *address { - Self::SYSTEM_ACCOUNT_QUERY => Some(query_account::query_account( - self, address, input, context, is_static, - )), - Self::SYSTEM_ACCOUNT_NEON_TOKEN => Some(neon_token::neon_token( - self, address, input, context, is_static, - )), - Self::SYSTEM_ACCOUNT_SPL_TOKEN => Some(spl_token::spl_token( - self, address, input, context, is_static, - )), + Self::SYSTEM_ACCOUNT_QUERY => { + Some(query_account::query_account(self, address, input, context, is_static).await) + } + Self::SYSTEM_ACCOUNT_NEON_TOKEN => { + Some(neon_token::neon_token(self, address, input, context, is_static).await) + } + Self::SYSTEM_ACCOUNT_SPL_TOKEN => { + Some(spl_token::spl_token(self, address, input, context, is_static).await) + } Self::SYSTEM_ACCOUNT_METAPLEX => { - Some(metaplex::metaplex(self, address, input, context, is_static)) + Some(metaplex::metaplex(self, address, input, context, is_static).await) } _ => None, } diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 0f33d5f24..4247acd0c 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use arrayref::array_ref; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{program_pack::Pack, pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; use spl_associated_token_account::get_associated_token_address; @@ -18,8 +19,9 @@ use crate::{ //-------------------------------------------------- const NEON_TOKEN_METHOD_WITHDRAW_ID: &[u8; 4] = &[0x8e, 0x19, 0x89, 0x9e]; -pub fn neon_token( - state: &mut ExecutorState, +#[maybe_async] +pub async fn neon_token( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -46,7 +48,7 @@ pub fn neon_token( let destination = array_ref![rest, 0, 32]; let destination = Pubkey::new_from_array(*destination); - withdraw(state, source, destination, context.value)?; + withdraw(state, source, destination, context.value).await?; let mut output = vec![0_u8; 32]; output[31] = 1; // return true @@ -58,8 +60,9 @@ pub fn neon_token( Err(Error::UnknownPrecompileMethodSelector(*address, *method_id)) } -fn withdraw( - state: &mut ExecutorState, +#[maybe_async] +async fn withdraw( + state: &mut ExecutorState<'_, B>, source: Address, target: Pubkey, value: U256, @@ -87,7 +90,7 @@ fn withdraw( } let target_token = get_associated_token_address(&target, state.backend.neon_token_mint()); - let account = state.external_account(target_token)?; + let account = state.external_account(target_token).await?; if !spl_token::check_id(&account.owner) { use spl_associated_token_account::instruction::create_associated_token_account; diff --git a/evm_loader/program/src/executor/precompile_extension/query_account.rs b/evm_loader/program/src/executor/precompile_extension/query_account.rs index 637e7d80f..37ae38f06 100644 --- a/evm_loader/program/src/executor/precompile_extension/query_account.rs +++ b/evm_loader/program/src/executor/precompile_extension/query_account.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use arrayref::{array_ref, array_refs}; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use crate::{ @@ -30,8 +31,9 @@ use crate::{ // "a9dbaf25": "length(bytes32)", // "7dd6c1a0": "data(bytes32,uint64,uint64)", -pub fn query_account( - state: &mut ExecutorState, +#[maybe_async] +pub async fn query_account( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -57,23 +59,23 @@ pub fn query_account( } [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { debug_print!("query_account.owner({})", &account_address); - account_owner(state, &account_address) + account_owner(state, &account_address).await } [0xaa, 0x8b, 0x99, 0xd2] | [0xa9, 0xdb, 0xaf, 0x25] => { debug_print!("query_account.length({})", &account_address); - account_data_length(state, &account_address) + account_data_length(state, &account_address).await } [0x74, 0x8f, 0x2d, 0x8a] | [0x62, 0x73, 0x44, 0x8f] => { debug_print!("query_account.lamports({})", &account_address); - account_lamports(state, &account_address) + account_lamports(state, &account_address).await } [0xc2, 0x19, 0xa7, 0x85] | [0xe6, 0xbe, 0xf4, 0x88] => { debug_print!("query_account.executable({})", &account_address); - account_is_executable(state, &account_address) + account_is_executable(state, &account_address).await } [0xc4, 0xd3, 0x69, 0xb5] | [0x8b, 0xb9, 0xe6, 0xf4] => { debug_print!("query_account.rent_epoch({})", &account_address); - account_rent_epoch(state, &account_address) + account_rent_epoch(state, &account_address).await } [0x43, 0xca, 0x51, 0x61] | [0x7d, 0xd6, 0xc1, 0xa0] => { let arguments = array_ref![rest, 0, 64]; @@ -86,11 +88,11 @@ pub fn query_account( offset, length ); - account_data(state, &account_address, offset, length) + account_data(state, &account_address, offset, length).await } [0xb6, 0x4a, 0x09, 0x7e] => { debug_print!("query_account.info({})", &account_address); - account_info(state, &account_address) + account_info(state, &account_address).await } _ => { debug_print!("query_account UNKNOWN {:?}", method_id); @@ -100,25 +102,29 @@ pub fn query_account( } #[allow(clippy::unnecessary_wraps)] -fn account_owner( - state: &mut ExecutorState, +#[maybe_async] +async fn account_owner( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let owner = state .backend - .map_solana_account(address, |info| info.owner.to_bytes()); + .map_solana_account(address, |info| info.owner.to_bytes()) + .await; Ok(owner.to_vec()) } #[allow(clippy::unnecessary_wraps)] -fn account_lamports( - state: &mut ExecutorState, +#[maybe_async] +async fn account_lamports( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let lamports: U256 = state .backend .map_solana_account(address, |info| **info.lamports.borrow()) + .await .into(); let bytes = lamports.to_be_bytes().to_vec(); @@ -127,13 +133,15 @@ fn account_lamports( } #[allow(clippy::unnecessary_wraps)] -fn account_rent_epoch( - state: &mut ExecutorState, +#[maybe_async] +async fn account_rent_epoch( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let epoch: U256 = state .backend .map_solana_account(address, |info| info.rent_epoch) + .await .into(); let bytes = epoch.to_be_bytes().to_vec(); @@ -142,13 +150,15 @@ fn account_rent_epoch( } #[allow(clippy::unnecessary_wraps)] -fn account_is_executable( - state: &mut ExecutorState, +#[maybe_async] +async fn account_is_executable( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let executable: U256 = state .backend .map_solana_account(address, |info| info.executable) + .await .into(); let bytes = executable.to_be_bytes().to_vec(); @@ -157,13 +167,15 @@ fn account_is_executable( } #[allow(clippy::unnecessary_wraps)] -fn account_data_length( - state: &mut ExecutorState, +#[maybe_async] +async fn account_data_length( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let length: U256 = state .backend .map_solana_account(address, |info| info.data.borrow().len()) + .await .try_into()?; let bytes = length.to_be_bytes().to_vec(); @@ -172,8 +184,9 @@ fn account_data_length( } #[allow(clippy::unnecessary_wraps)] -fn account_data( - state: &mut ExecutorState, +#[maybe_async] +async fn account_data( + state: &mut ExecutorState<'_, B>, address: &Pubkey, offset: usize, length: usize, @@ -192,12 +205,14 @@ fn account_data( .get(offset..offset + length) .map(<[u8]>::to_vec) }) + .await .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) } #[allow(clippy::unnecessary_wraps)] -fn account_info( - state: &mut ExecutorState, +#[maybe_async] +async fn account_info( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { fn to_solidity_account_value(info: &AccountInfo) -> Vec { @@ -216,7 +231,8 @@ fn account_info( let info = state .backend - .map_solana_account(address, to_solidity_account_value); + .map_solana_account(address, to_solidity_account_value) + .await; Ok(info) } diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 674f95419..7d3502b33 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -1,6 +1,7 @@ use std::convert::{Into, TryInto}; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{ program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, system_instruction, system_program, sysvar::Sysvar, @@ -33,8 +34,9 @@ use crate::{ // [0x7c, 0x0e, 0xb8, 0x10] : "transferWithSeed(bytes32,bytes32,bytes32,uint64)" #[allow(clippy::too_many_lines)] -pub fn spl_token( - state: &mut ExecutorState, +#[maybe_async] +pub async fn spl_token( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -63,7 +65,7 @@ pub fn spl_token( let seed = read_salt(input)?; let decimals = read_u8(&input[32..])?; - initialize_mint(context, state, seed, decimals, None, None) + initialize_mint(context, state, seed, decimals, None, None).await } [0xc3, 0xf3, 0xf2, 0xf2] => { // initializeMint(bytes32 seed, uint8 decimals, bytes32 mint_authority, bytes32 freeze_authority) @@ -83,6 +85,7 @@ pub fn spl_token( Some(mint_authority), Some(freeze_authority), ) + .await } [0xda, 0xa1, 0x2c, 0x5c] => { // initializeAccount(bytes32 seed, bytes32 mint) @@ -93,7 +96,7 @@ pub fn spl_token( let seed = read_salt(input)?; let mint = read_pubkey(&input[32..])?; - initialize_account(context, state, seed, mint, None) + initialize_account(context, state, seed, mint, None).await } [0xfc, 0x86, 0xb7, 0x17] => { // initializeAccount(bytes32 seed, bytes32 mint, bytes32 owner) @@ -104,7 +107,7 @@ pub fn spl_token( let seed = read_salt(input)?; let mint = read_pubkey(&input[32..])?; let owner = read_pubkey(&input[64..])?; - initialize_account(context, state, seed, mint, Some(owner)) + initialize_account(context, state, seed, mint, Some(owner)).await } [0x57, 0x82, 0xa0, 0x43] => { // closeAccount(bytes32 account) @@ -209,17 +212,17 @@ pub fn spl_token( [0x6d, 0xa9, 0xde, 0x75] => { // isSystemAccount(bytes32 account) let account = read_pubkey(input)?; - is_system_account(context, state, account) + is_system_account(context, state, account).await } [0xd1, 0xde, 0x50, 0x11] => { // getAccount(bytes32 account) let account = read_pubkey(input)?; - get_account(context, state, account) + get_account(context, state, account).await } [0xa2, 0xce, 0x9c, 0x1f] => { // getMint(bytes32 account) let account = read_pubkey(input)?; - get_mint(context, state, account) + get_mint(context, state, account).await } _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), } @@ -281,9 +284,10 @@ fn create_account( Ok(()) } -fn initialize_mint( +#[maybe_async] +async fn initialize_mint( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, seed: &[u8], decimals: u8, mint_authority: Option, @@ -302,7 +306,7 @@ fn initialize_mint( state.backend.program_id(), ); - let account = state.external_account(mint_key)?; + let account = state.external_account(mint_key).await?; if !system_program::check_id(&account.owner) { return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); } @@ -329,9 +333,10 @@ fn initialize_mint( Ok(mint_key.to_bytes().to_vec()) } -fn initialize_account( +#[maybe_async] +async fn initialize_account( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, seed: &[u8], mint: Pubkey, owner: Option, @@ -349,7 +354,7 @@ fn initialize_account( state.backend.program_id(), ); - let account = state.external_account(account_key)?; + let account = state.external_account(account_key).await?; if !system_program::check_id(&account.owner) { return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); } @@ -652,12 +657,13 @@ fn find_account( Ok(account_key.to_bytes().to_vec()) } -fn is_system_account( +#[maybe_async] +async fn is_system_account( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, account: Pubkey, ) -> Result> { - let account = state.external_account(account)?; + let account = state.external_account(account).await?; if system_program::check_id(&account.owner) { let mut result = vec![0_u8; 32]; result[31] = 1; // return true @@ -668,12 +674,13 @@ fn is_system_account( } } -fn get_account( +#[maybe_async] +async fn get_account( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, account: Pubkey, ) -> Result> { - let account = state.external_account(account)?; + let account = state.external_account(account).await?; let token = if spl_token::check_id(&account.owner) { spl_token::state::Account::unpack(&account.data)? } else if system_program::check_id(&account.owner) { @@ -702,12 +709,13 @@ fn get_account( Ok(result.to_vec()) } -fn get_mint( +#[maybe_async] +async fn get_mint( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, account: Pubkey, ) -> Result> { - let account = state.external_account(account)?; + let account = state.external_account(account).await?; let mint = if spl_token::check_id(&account.owner) { spl_token::state::Mint::unpack(&account.data)? } else if system_program::check_id(&account.owner) { diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 031d855f3..0d04a36c1 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::collections::BTreeMap; use ethnum::{AsU256, U256}; +use maybe_async::maybe_async; use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; @@ -103,9 +104,8 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { self.actions.push(action); } - pub fn external_account(&self, address: Pubkey) -> Result { - let mut cache = self.cache.borrow_mut(); - + #[maybe_async] + pub async fn external_account(&self, address: Pubkey) -> Result { let metas = self .actions .iter() @@ -120,18 +120,30 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { .collect::>(); if !metas.iter().any(|m| (m.pubkey == address) && m.is_writable) { - return Ok(cache.get_account_or_insert(address, self.backend).clone()); + insert_account_if_not_present(&self.cache, address, self.backend).await; + return Ok(self + .cache + .borrow() + .solana_accounts + .get(&address) + .unwrap() + .clone()); } - let mut accounts = metas - .into_iter() - .map(|m| { - ( - m.pubkey, - cache.get_account_or_insert(m.pubkey, self.backend).clone(), - ) - }) - .collect::>(); + let mut accounts = BTreeMap::::new(); + + for m in metas { + insert_account_if_not_present(&self.cache, m.pubkey, self.backend).await; + accounts.insert( + m.pubkey, + self.cache + .borrow() + .solana_accounts + .get(&m.pubkey) + .unwrap() + .clone(), + ); + } for action in &self.actions { if let Action::ExternalInstruction { @@ -171,14 +183,30 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } } +#[maybe_async] +async fn insert_account_if_not_present( + cache: &RefCell, + key: Pubkey, + backend: &B, +) { + if !cache.borrow().solana_accounts.contains_key(&key) { + let owned_account_info = backend.clone_solana_account(&key).await; + cache + .borrow_mut() + .solana_accounts + .insert(key, owned_account_info); + } +} + +#[maybe_async(?Send)] impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { fn chain_id(&self) -> U256 { let chain_id = self.backend.chain_id(); U256::from(chain_id) } - fn nonce(&self, from_address: &Address) -> Result { - let mut nonce = self.backend.nonce(from_address); + async fn nonce(&self, from_address: &Address) -> Result { + let mut nonce = self.backend.nonce(from_address).await; for action in &self.actions { if let Action::EvmIncrementNonce { address } = action { @@ -198,8 +226,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn balance(&self, from_address: &Address) -> Result { - let mut balance = self.backend.balance(from_address); + async fn balance(&self, from_address: &Address) -> Result { + let mut balance = self.backend.balance(from_address).await; for action in &self.actions { match action { @@ -228,7 +256,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(balance) } - fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()> { + async fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()> { if value == U256::ZERO { return Ok(()); } @@ -237,7 +265,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(()); } - if self.balance(&source)? < value { + if self.balance(&source).await? < value { return Err(Error::InsufficientBalance(source, value)); } @@ -251,7 +279,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn code_size(&self, from_address: &Address) -> Result { + async fn code_size(&self, from_address: &Address) -> Result { if self.is_precompile_extension(from_address) { return Ok(1); // This is required in order to make a normal call to an extension contract } @@ -264,10 +292,10 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.code_size(from_address)) + Ok(self.backend.code_size(from_address).await) } - fn code_hash(&self, from_address: &Address) -> Result<[u8; 32]> { + async fn code_hash(&self, from_address: &Address) -> Result<[u8; 32]> { use solana_program::keccak::hash; for action in &self.actions { @@ -278,10 +306,10 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.code_hash(from_address)) + Ok(self.backend.code_hash(from_address).await) } - fn code(&self, from_address: &Address) -> Result { + async fn code(&self, from_address: &Address) -> Result { for action in &self.actions { if let Action::EvmSetCode { address, code } = action { if from_address == address { @@ -290,7 +318,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.code(from_address)) + Ok(self.backend.code(from_address).await) } fn set_code(&mut self, address: Address, code: crate::evm::Buffer) -> Result<()> { @@ -317,7 +345,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn storage(&self, from_address: &Address, from_index: &U256) -> Result<[u8; 32]> { + async fn storage(&self, from_address: &Address, from_index: &U256) -> Result<[u8; 32]> { for action in self.actions.iter().rev() { if let Action::EvmSetStorage { address, @@ -331,7 +359,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.storage(from_address, from_index)) + Ok(self.backend.storage(from_address, from_index).await) } fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { @@ -345,7 +373,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn block_hash(&self, number: U256) -> Result<[u8; 32]> { + async fn block_hash(&self, number: U256) -> Result<[u8; 32]> { // geth: // - checks the overflow // - converts to u64 @@ -367,7 +395,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(<[u8; 32]>::default()); } - Ok(self.backend.block_hash(number)) + Ok(self.backend.block_hash(number).await) } fn block_number(&self) -> Result { @@ -380,11 +408,11 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(cache.block_timestamp) } - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&solana_program::account_info::AccountInfo) -> R, { - self.backend.map_solana_account(address, action) + self.backend.map_solana_account(address, action).await } fn snapshot(&mut self) { @@ -412,7 +440,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { .expect("Fatal Error: Inconsistent EVM Call Stack"); } - fn precompile_extension( + async fn precompile_extension( &mut self, context: &Context, address: &Address, @@ -420,5 +448,6 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { is_static: bool, ) -> Option>> { self.call_precompile_extension(context, address, data, is_static) + .await } } diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 28acefcb4..3fdd83405 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -54,13 +54,7 @@ pub fn execute<'a>( let (exit_reason, apply_state) = { let mut backend = ExecutorState::new(account_storage); - let mut evm = Machine::new( - trx, - caller_address, - &mut backend, - #[cfg(feature = "tracing")] - None, - )?; + let mut evm = Machine::new(trx, caller_address, &mut backend)?; let (result, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 3396ec5d0..7b1aa8ef6 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -38,13 +38,7 @@ pub fn do_begin<'a>( account_storage.block_accounts(true); let mut backend = ExecutorState::new(account_storage); - let evm = Machine::new( - trx, - caller, - &mut backend, - #[cfg(feature = "tracing")] - None, - )?; + let evm = Machine::new(trx, caller, &mut backend)?; serialize_evm_state(&mut storage, &backend, &evm)?; diff --git a/evm_loader/program/src/lib.rs b/evm_loader/program/src/lib.rs index aaa79338a..005757f81 100644 --- a/evm_loader/program/src/lib.rs +++ b/evm_loader/program/src/lib.rs @@ -6,7 +6,8 @@ #![allow( clippy::module_name_repetitions, clippy::missing_const_for_fn, - clippy::use_self + clippy::use_self, + clippy::future_not_send )] #![allow(missing_docs, clippy::missing_panics_doc, clippy::missing_errors_doc)] @@ -18,11 +19,13 @@ pub mod error; pub mod account; pub mod account_storage; pub mod config; +#[cfg(target_os = "solana")] pub mod entrypoint; pub mod evm; pub mod executor; pub mod external_programs; pub mod gasometer; +#[cfg(target_os = "solana")] pub mod instruction; pub mod state_account; pub mod types; diff --git a/evm_loader/program/src/state_account.rs b/evm_loader/program/src/state_account.rs index e93407ba1..7e4c520c7 100644 --- a/evm_loader/program/src/state_account.rs +++ b/evm_loader/program/src/state_account.rs @@ -1,15 +1,23 @@ -use crate::{ - account::{program, EthereumAccount, FinalizedState, Holder, Incinerator, Operator, State}, - config::OPERATOR_PRIORITY_SLOTS, - error::Error, - types::{Address, Transaction}, +#[cfg(target_os = "solana")] +use { + crate::account::program, + crate::types::{Address, Transaction}, + ethnum::U256, }; -use ethnum::U256; -use solana_program::{ - account_info::AccountInfo, clock::Clock, program_error::ProgramError, pubkey::Pubkey, - sysvar::Sysvar, + +use { + crate::account::EthereumAccount, + crate::account::Holder, + crate::config::OPERATOR_PRIORITY_SLOTS, + crate::error::Error, + solana_program::account_info::AccountInfo, + solana_program::clock::Clock, + solana_program::sysvar::Sysvar, + std::cell::{Ref, RefMut}, }; -use std::cell::{Ref, RefMut}; + +use crate::account::{FinalizedState, Incinerator, Operator, State}; +use solana_program::{program_error::ProgramError, pubkey::Pubkey}; const ACCOUNT_CHUNK_LEN: usize = 1 + 1 + 32; @@ -34,6 +42,7 @@ impl<'a> FinalizedState<'a> { } impl<'a> State<'a> { + #[cfg(target_os = "solana")] pub fn new( program_id: &'a Pubkey, info: &'a AccountInfo<'a>, @@ -136,6 +145,7 @@ impl<'a> State<'a> { Ok(finalized) } + #[cfg(target_os = "solana")] fn make_deposit( &self, system_program: &program::System<'a>, @@ -186,6 +196,7 @@ impl<'a> State<'a> { Ok(accounts) } + #[cfg(target_os = "solana")] fn write_blocked_accounts( &mut self, program_id: &Pubkey, diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 422350278..06000d18f 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -6,5 +6,6 @@ pub use transaction::Transaction; pub use transaction::TransactionPayload; mod address; +#[cfg(not(target_os = "solana"))] pub mod hexbytes; mod transaction; diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index 7d4d5a664..b6d1e202f 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -20,6 +20,7 @@ impl rlp::Decodable for StorageKey { } } +#[cfg(not(target_os = "solana"))] impl TryFrom for StorageKey { type Error = String;