diff --git a/Dockerfile b/Dockerfile
index 55744efaed..969b010e42 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,13 +18,13 @@ ENV NEON_REVISION=${REVISION}
RUN cargo fmt --check && \
cargo clippy --release && \
cargo build --release && \
- cargo build-bpf --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \
- cargo build-bpf --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \
- cargo build-bpf --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \
- cargo build-bpf --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \
- cargo build-bpf --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \
- cargo build-bpf --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \
- cargo build-bpf --features ci --dump
+ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \
+ cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \
+ cargo build-bpf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \
+ cargo build-bpf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \
+ cargo build-bpf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \
+ cargo build-bpf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \
+ cargo build-bpf --manifest-path program/Cargo.toml --features ci --dump
# Build Solidity contracts
FROM ethereum/solc:0.8.0 AS solc
@@ -48,7 +48,8 @@ FROM ${SOLANA_IMAGE} AS solana
FROM ubuntu:20.04 AS base
WORKDIR /opt
RUN apt-get update && \
- DEBIAN_FRONTEND=noninteractive apt-get -y install vim less openssl ca-certificates curl python3 python3-pip parallel && \
+ apt-get upgrade -y && \
+ DEBIAN_FRONTEND=noninteractive apt-get -y install vim less openssl libssl-dev ca-certificates curl python3 python3-pip parallel && \
rm -rf /var/lib/apt/lists/*
COPY tests/requirements.txt /tmp/
@@ -77,6 +78,8 @@ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader
COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader-dump.txt /opt/
COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-cli /opt/
COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api /opt/
+COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-rpc /opt/
+COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/libneon_lib.so /opt/libs/current/
COPY --from=solana /usr/bin/spl-token /opt/spl-token
COPY --from=contracts /opt/ /opt/solidity/
COPY --from=contracts /usr/bin/solc /usr/bin/solc
@@ -95,4 +98,4 @@ COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json
COPY ci/keys/ /opt/keys
#ENV CONTRACTS_DIR=/opt/solidity/
-ENV PATH=/opt/solana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
+ENV PATH=/opt/solana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
\ No newline at end of file
diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock
index 6787d170d6..79b46f1717 100644
--- a/evm_loader/Cargo.lock
+++ b/evm_loader/Cargo.lock
@@ -12,6 +12,54 @@ dependencies = [
"regex",
]
+[[package]]
+name = "abi_stable"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467388fe07f5a809f4df42226142cadd5a7706810b76a0896fd68d156b1ea886"
+dependencies = [
+ "abi_stable_derive",
+ "abi_stable_shared",
+ "const_panic",
+ "core_extensions",
+ "crossbeam-channel",
+ "generational-arena",
+ "libloading",
+ "lock_api",
+ "parking_lot",
+ "paste",
+ "repr_offset",
+ "rustc_version",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "abi_stable_derive"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aecd3efa5a5294f5c67913d45f985ccb382b3c93327581529610eeecdf4821a"
+dependencies = [
+ "abi_stable_shared",
+ "as_derive_utils",
+ "core_extensions",
+ "proc-macro2 1.0.66",
+ "quote 1.0.32",
+ "rustc_version",
+ "syn 1.0.109",
+ "typed-arena",
+]
+
+[[package]]
+name = "abi_stable_shared"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63"
+dependencies = [
+ "core_extensions",
+]
+
[[package]]
name = "actix-codec"
version = "0.5.1"
@@ -450,6 +498,18 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
+[[package]]
+name = "as_derive_utils"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4"
+dependencies = [
+ "core_extensions",
+ "proc-macro2 1.0.66",
+ "quote 1.0.32",
+ "syn 1.0.109",
+]
+
[[package]]
name = "ascii"
version = "0.9.3"
@@ -526,6 +586,15 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "async-ffi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ed5a937a789391ebc1c77d3a15b060e0d100e6d7c483a2af3f250d6b8dc2a23"
+dependencies = [
+ "abi_stable",
+]
+
[[package]]
name = "async-mutex"
version = "1.4.0"
@@ -537,9 +606,9 @@ dependencies = [
[[package]]
name = "async-trait"
-version = "0.1.73"
+version = "0.1.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
+checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.32",
@@ -587,6 +656,15 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+[[package]]
+name = "beef"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "bincode"
version = "1.3.3"
@@ -1169,6 +1247,12 @@ dependencies = [
"unicode-xid 0.2.4",
]
+[[package]]
+name = "const_panic"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b"
+
[[package]]
name = "constant_time_eq"
version = "0.3.0"
@@ -1208,6 +1292,21 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+[[package]]
+name = "core_extensions"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92c71dc07c9721607e7a16108336048ee978c3a8b129294534272e8bac96c0ee"
+dependencies = [
+ "core_extensions_proc_macros",
+]
+
+[[package]]
+name = "core_extensions_proc_macros"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6"
+
[[package]]
name = "cpufeatures"
version = "0.2.6"
@@ -1673,6 +1772,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+[[package]]
+name = "erased-serde"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "errno"
version = "0.3.1"
@@ -1750,6 +1858,15 @@ dependencies = [
"toml",
]
+[[package]]
+name = "extensions"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "258f70bd2b060d448403a66d420e81dcac3e5247a4928a887404a5e03715e2e0"
+dependencies = [
+ "fxhash",
+]
+
[[package]]
name = "fastrand"
version = "1.9.0"
@@ -1807,9 +1924,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
@@ -1909,6 +2026,24 @@ dependencies = [
"slab",
]
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "generational-arena"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7"
+dependencies = [
+ "cfg-if",
+]
+
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -2064,6 +2199,12 @@ dependencies = [
"unicode-segmentation",
]
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -2215,7 +2356,9 @@ dependencies = [
"futures-util",
"http",
"hyper",
+ "log",
"rustls 0.21.7",
+ "rustls-native-certs",
"tokio",
"tokio-rustls 0.24.1",
]
@@ -2265,9 +2408,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@@ -2396,6 +2539,76 @@ dependencies = [
"serde_json",
]
+[[package]]
+name = "jsonrpc-v2"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "759affe8550a30591c68f5e85d1784f24dc65217d2cca765949857f844fcecb0"
+dependencies = [
+ "actix-service",
+ "actix-web",
+ "async-trait",
+ "bytes",
+ "erased-serde",
+ "extensions",
+ "futures",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "jsonrpsee-core"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51f45d37af23707750136379f6799e76ebfcf2d425ec4e36d0deb7921da5e65c"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "beef",
+ "futures-util",
+ "hyper",
+ "jsonrpsee-types",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "jsonrpsee-http-client"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02308562f2e8162a32f8d6c3dc19c29c858d5d478047c886a5c3c25b5f7fa868"
+dependencies = [
+ "async-trait",
+ "hyper",
+ "hyper-rustls",
+ "jsonrpsee-core",
+ "jsonrpsee-types",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tokio",
+ "tower",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "jsonrpsee-types"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05eaff23af19f10ba6fbb76519bed6da4d3b9bbaef13d39b7c2b6c14e532d27e"
+dependencies = [
+ "anyhow",
+ "beef",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tracing",
+]
+
[[package]]
name = "keccak"
version = "0.1.3"
@@ -2435,6 +2648,16 @@ dependencies = [
"pkg-config",
]
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
[[package]]
name = "libsecp256k1"
version = "0.6.0"
@@ -2828,7 +3051,9 @@ dependencies = [
name = "neon-lib"
version = "0.1.0"
dependencies = [
+ "abi_stable",
"anyhow",
+ "async-ffi",
"async-trait",
"bincode",
"bs58",
@@ -2839,7 +3064,9 @@ dependencies = [
"evm-loader",
"goblin 0.6.1",
"hex",
+ "lazy_static",
"log",
+ "neon-lib-interface",
"rand 0.8.5",
"scroll",
"serde",
@@ -2852,11 +3079,62 @@ dependencies = [
"solana-transaction-status",
"spl-associated-token-account 1.1.3",
"spl-token 3.5.0",
+ "strum",
+ "strum_macros",
"thiserror",
"tokio",
"tracing",
]
+[[package]]
+name = "neon-lib-interface"
+version = "0.1.0"
+dependencies = [
+ "abi_stable",
+ "async-ffi",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "neon-rpc"
+version = "0.1.0"
+dependencies = [
+ "actix-web",
+ "build-info",
+ "build-info-build",
+ "clap 2.34.0",
+ "jsonrpc-v2",
+ "neon-lib",
+ "neon-lib-interface",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "tracing-appender",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "neon-rpc-client"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "build-info",
+ "jsonrpc-v2",
+ "jsonrpsee-core",
+ "jsonrpsee-http-client",
+ "jsonrpsee-types",
+ "neon-lib",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tokio",
+]
+
[[package]]
name = "nix"
version = "0.26.2"
@@ -3226,9 +3504,9 @@ dependencies = [
[[package]]
name = "percent-encoding"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "percentage"
@@ -3239,6 +3517,26 @@ dependencies = [
"num",
]
+[[package]]
+name = "pin-project"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
+dependencies = [
+ "proc-macro2 1.0.66",
+ "quote 1.0.32",
+ "syn 2.0.28",
+]
+
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -3658,6 +3956,15 @@ version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+[[package]]
+name = "repr_offset"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea"
+dependencies = [
+ "tstr",
+]
+
[[package]]
name = "reqwest"
version = "0.11.20"
@@ -3950,7 +4257,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c"
dependencies = [
- "heck",
+ "heck 0.3.3",
"proc-macro2 1.0.66",
"quote 1.0.32",
"syn 1.0.109",
@@ -3981,18 +4288,18 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.17"
+version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
dependencies = [
"serde",
]
[[package]]
name = "serde"
-version = "1.0.186"
+version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1"
+checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
dependencies = [
"serde_derive",
]
@@ -4008,9 +4315,9 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.186"
+version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670"
+checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.32",
@@ -5439,6 +5746,25 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+[[package]]
+name = "strum"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
+
+[[package]]
+name = "strum_macros"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2 1.0.66",
+ "quote 1.0.32",
+ "rustversion",
+ "syn 2.0.28",
+]
+
[[package]]
name = "subtle"
version = "2.4.1"
@@ -5529,18 +5855,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
-version = "1.0.40"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.40"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.32",
@@ -5769,7 +6095,9 @@ 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",
@@ -5869,6 +6197,21 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+[[package]]
+name = "tstr"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e"
+dependencies = [
+ "tstr_proc_macros",
+]
+
+[[package]]
+name = "tstr_proc_macros"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a"
+
[[package]]
name = "tungstenite"
version = "0.17.3"
@@ -5891,6 +6234,12 @@ dependencies = [
"webpki-roots 0.22.6",
]
+[[package]]
+name = "typed-arena"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
+
[[package]]
name = "typenum"
version = "1.16.0"
@@ -5985,9 +6334,9 @@ dependencies = [
[[package]]
name = "url"
-version = "2.3.1"
+version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
"form_urlencoded",
"idna",
diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml
index 5081e7429c..b00b0b1b07 100644
--- a/evm_loader/Cargo.toml
+++ b/evm_loader/Cargo.toml
@@ -1,9 +1,12 @@
[workspace]
resolver = "2"
members = [
- 'api',
- 'cli',
- 'lib',
- 'program',
- 'program-macro'
+ 'api',
+ 'cli',
+ 'lib',
+ 'lib-interface',
+ 'rpc',
+ 'rpc-client',
+ 'program',
+ 'program-macro',
]
diff --git a/evm_loader/lib-interface/.gitignore b/evm_loader/lib-interface/.gitignore
new file mode 100644
index 0000000000..2f7896d1d1
--- /dev/null
+++ b/evm_loader/lib-interface/.gitignore
@@ -0,0 +1 @@
+target/
diff --git a/evm_loader/lib-interface/Cargo.lock b/evm_loader/lib-interface/Cargo.lock
new file mode 100644
index 0000000000..7c3935937d
--- /dev/null
+++ b/evm_loader/lib-interface/Cargo.lock
@@ -0,0 +1,474 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "abi_stable"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f69d9465d88d24382d43fa68335a92fe9d3c53a918549c693403ed9a85eff50"
+dependencies = [
+ "abi_stable_derive",
+ "abi_stable_shared",
+ "const_panic",
+ "core_extensions",
+ "crossbeam-channel",
+ "generational-arena",
+ "libloading",
+ "lock_api",
+ "parking_lot",
+ "paste",
+ "repr_offset",
+ "rustc_version",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "abi_stable_derive"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aecd3efa5a5294f5c67913d45f985ccb382b3c93327581529610eeecdf4821a"
+dependencies = [
+ "abi_stable_shared",
+ "as_derive_utils",
+ "core_extensions",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 1.0.109",
+ "typed-arena",
+]
+
+[[package]]
+name = "abi_stable_shared"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63"
+dependencies = [
+ "core_extensions",
+]
+
+[[package]]
+name = "as_derive_utils"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4"
+dependencies = [
+ "core_extensions",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "async-ffi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ed5a937a789391ebc1c77d3a15b060e0d100e6d7c483a2af3f250d6b8dc2a23"
+dependencies = [
+ "abi_stable",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "const_panic"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b"
+
+[[package]]
+name = "core_extensions"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92c71dc07c9721607e7a16108336048ee978c3a8b129294534272e8bac96c0ee"
+dependencies = [
+ "core_extensions_proc_macros",
+]
+
+[[package]]
+name = "core_extensions_proc_macros"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6"
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "generational-arena"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601"
+dependencies = [
+ "cfg-if 0.1.10",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+
+[[package]]
+name = "libc"
+version = "0.2.144"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if 1.0.0",
+ "winapi",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "neon-interface"
+version = "0.1.0"
+dependencies = [
+ "abi_stable",
+ "async-ffi",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-sys",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "repr_offset"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea"
+dependencies = [
+ "tstr",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
+[[package]]
+name = "serde"
+version = "1.0.163"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.163"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.16",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.96"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.16",
+]
+
+[[package]]
+name = "tstr"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e"
+dependencies = [
+ "tstr_proc_macros",
+]
+
+[[package]]
+name = "tstr_proc_macros"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a"
+
+[[package]]
+name = "typed-arena"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml
new file mode 100644
index 0000000000..1a1283d88d
--- /dev/null
+++ b/evm_loader/lib-interface/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "neon-lib-interface"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+abi_stable = "0.11.1"
+thiserror = "1"
+async-ffi = { version = "0.4.1", features = ["abi_stable"] }
+serde = "1.0.147"
+serde_json = "1.0.85"
diff --git a/evm_loader/lib-interface/src/lib.rs b/evm_loader/lib-interface/src/lib.rs
new file mode 100644
index 0000000000..fab07f3f7f
--- /dev/null
+++ b/evm_loader/lib-interface/src/lib.rs
@@ -0,0 +1,59 @@
+#![allow(non_camel_case_types)]
+
+pub mod types;
+
+use crate::types::RNeonEVMLibResult;
+use std::{collections::HashMap, path::Path};
+use thiserror::Error;
+
+use abi_stable::{
+ library::{LibraryError, RootModule},
+ package_version_strings,
+ std_types::{RStr, RString},
+ StableAbi,
+};
+
+#[repr(C)]
+#[derive(StableAbi)]
+#[sabi(kind(Prefix(prefix_ref = NeonEVMLib_Ref)))]
+#[sabi(missing_field(panic))]
+pub struct NeonEVMLib {
+ pub hash: extern "C" fn() -> RString,
+ pub get_version: extern "C" fn() -> RString,
+ pub get_build_info: extern "C" fn() -> RString,
+
+ pub invoke: for<'a> extern "C" fn(RStr<'a>, RStr<'a>) -> RNeonEVMLibResult<'a>,
+}
+
+impl RootModule for NeonEVMLib_Ref {
+ abi_stable::declare_root_module_statics! {NeonEVMLib_Ref}
+
+ const BASE_NAME: &'static str = "neon-lib-interface";
+ const NAME: &'static str = "neon-lib-interface";
+ const VERSION_STRINGS: abi_stable::sabi_types::VersionStrings = package_version_strings!();
+}
+
+#[derive(Error, Debug)]
+pub enum NeonEVMLibLoadError {
+ #[error("abi_stable library error")]
+ LibraryError(#[from] LibraryError),
+ #[error("IO error")]
+ IoError(#[from] std::io::Error),
+}
+
+pub fn load_libraries
(
+ directory: P,
+) -> Result, NeonEVMLibLoadError>
+where
+ P: AsRef,
+{
+ let paths = std::fs::read_dir(directory)?;
+ let mut result = HashMap::new();
+ for path in paths {
+ let lib = NeonEVMLib_Ref::load_from_file(&path?.path())?;
+ let hash = lib.hash()();
+
+ result.insert(hash.into_string(), lib);
+ }
+ Ok(result)
+}
diff --git a/evm_loader/lib-interface/src/types.rs b/evm_loader/lib-interface/src/types.rs
new file mode 100644
index 0000000000..c6f8f22fee
--- /dev/null
+++ b/evm_loader/lib-interface/src/types.rs
@@ -0,0 +1,12 @@
+use abi_stable::std_types::{RResult, RString};
+use async_ffi::LocalBorrowingFfiFuture;
+use serde::{Deserialize, Serialize};
+
+pub type RNeonEVMLibResult<'a> = LocalBorrowingFfiFuture<'a, RResult>;
+
+#[derive(Serialize, Deserialize, Clone, Debug)]
+pub struct NeonEVMLibError {
+ pub code: u32,
+ pub message: String,
+ pub data: Option,
+}
diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml
index cb3d166e6b..4bd4b90c30 100644
--- a/evm_loader/lib/Cargo.toml
+++ b/evm_loader/lib/Cargo.toml
@@ -9,15 +9,23 @@ edition = "2021"
thiserror = "1.0"
anyhow = "1.0"
bincode = "1.3.1"
-evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] }
+evm-loader = { path = "../program", default-features = false, features = [
+ "log",
+ "async-trait",
+ "serde_json",
+] }
solana-sdk = "=1.16.17"
solana-client = "=1.16.17"
solana-clap-utils = "=1.16.17"
solana-cli-config = "=1.16.17"
solana-cli = "=1.16.17"
solana-transaction-status = "=1.16.17"
-spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] }
-spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] }
+spl-token = { version = "~3.5", default-features = false, features = [
+ "no-entrypoint",
+] }
+spl-associated-token-account = { version = "~1.1", default-features = false, features = [
+ "no-entrypoint",
+] }
bs58 = "0.4.0"
hex = "0.4.2"
serde = "1.0.186"
@@ -32,6 +40,15 @@ clickhouse = "0.11.5"
tracing = "0.1"
async-trait = "0.1.73"
build-info = "0.0.31"
+neon-lib-interface = { path = "../lib-interface" }
+abi_stable = "0.11.2"
+async-ffi = { version = "0.4.1", features = ["abi_stable"] }
+lazy_static = "1.4.0"
+strum = "0.25.0"
+strum_macros = "0.25.3"
[build-dependencies]
build-info-build = "0.0.31"
+
+[lib]
+crate-type = ["cdylib", "lib"]
diff --git a/evm_loader/lib/src/abi/cancel_trx.rs b/evm_loader/lib/src/abi/cancel_trx.rs
new file mode 100644
index 0000000000..cd6f30513b
--- /dev/null
+++ b/evm_loader/lib/src/abi/cancel_trx.rs
@@ -0,0 +1,23 @@
+use super::params_to_neon_error;
+use crate::commands::cancel_trx::{self, CancelTrxReturn};
+use crate::{types::request_models::CancelTrxRequest, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let signer = context.signer()?;
+
+ let params: CancelTrxRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ cancel_trx::execute(
+ context.rpc_client,
+ signer.as_ref(),
+ config.evm_loader,
+ ¶ms.storage_account,
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/abi/collect_treasury.rs b/evm_loader/lib/src/abi/collect_treasury.rs
new file mode 100644
index 0000000000..cf631d667b
--- /dev/null
+++ b/evm_loader/lib/src/abi/collect_treasury.rs
@@ -0,0 +1,12 @@
+use crate::{
+ commands::collect_treasury::{self, CollectTreasuryReturn},
+ Config, Context, NeonResult,
+};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ _params: &str,
+) -> NeonResult {
+ collect_treasury::execute(config, context).await
+}
diff --git a/evm_loader/lib/src/abi/context.rs b/evm_loader/lib/src/abi/context.rs
new file mode 100644
index 0000000000..15647fa0b7
--- /dev/null
+++ b/evm_loader/lib/src/abi/context.rs
@@ -0,0 +1,53 @@
+use solana_client::nonblocking::rpc_client::RpcClient;
+
+use crate::{
+ rpc::{self, CallDbClient},
+ types::TracerDb,
+ Config, NeonError,
+};
+use std::sync::Arc;
+
+pub struct AbiContext {
+ pub tracer_db: TracerDb,
+ pub rpc_client: Arc,
+ pub config: Config,
+}
+
+impl AbiContext {
+ pub fn new(config: Config) -> Result {
+ let db_config = config
+ .db_config
+ .as_ref()
+ .ok_or(NeonError::LoadingDBConfigError)?;
+ Ok(Self {
+ tracer_db: TracerDb::new(db_config),
+ rpc_client: Arc::new(RpcClient::new_with_commitment(
+ config.json_rpc_url.clone(),
+ config.commitment,
+ )),
+ config,
+ })
+ }
+}
+
+pub async fn build_rpc_client(
+ context: &AbiContext,
+ slot: Option,
+ tx_index_in_block: Option,
+) -> Result, NeonError> {
+ if let Some(slot) = slot {
+ return build_call_db_client(context, slot, tx_index_in_block).await;
+ }
+
+ Ok(context.rpc_client.clone())
+}
+
+pub async fn build_call_db_client(
+ context: &AbiContext,
+ slot: u64,
+ tx_index_in_block: Option,
+) -> Result, NeonError> {
+ Ok(Arc::new(
+ CallDbClient::new(context.tracer_db.clone(), slot, tx_index_in_block).await?,
+ ))
+}
diff --git a/evm_loader/lib/src/abi/create_ether_account.rs b/evm_loader/lib/src/abi/create_ether_account.rs
new file mode 100644
index 0000000000..664ef7b0b3
--- /dev/null
+++ b/evm_loader/lib/src/abi/create_ether_account.rs
@@ -0,0 +1,34 @@
+use solana_client::nonblocking::rpc_client::RpcClient;
+
+use super::params_to_neon_error;
+use crate::commands::create_ether_account::CreateEtherAccountReturn;
+use crate::{
+ commands::create_ether_account::{self},
+ context::Context,
+ types::request_models::CreateEtherAccountRequest,
+ Config, NeonResult,
+};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let signer = context.signer()?;
+ let rpc_client = context
+ .rpc_client
+ .as_any()
+ .downcast_ref::()
+ .unwrap();
+
+ let params: CreateEtherAccountRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ create_ether_account::execute(
+ rpc_client,
+ config.evm_loader,
+ signer.as_ref(),
+ ¶ms.ether,
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/abi/deposit.rs b/evm_loader/lib/src/abi/deposit.rs
new file mode 100644
index 0000000000..eb9c2c0fe3
--- /dev/null
+++ b/evm_loader/lib/src/abi/deposit.rs
@@ -0,0 +1,31 @@
+use solana_client::nonblocking::rpc_client::RpcClient;
+
+use super::params_to_neon_error;
+use crate::commands::deposit::{self, DepositReturn};
+use crate::{types::request_models::DepositRequest, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let signer = context.signer()?;
+ let rpc_client = context
+ .rpc_client
+ .as_any()
+ .downcast_ref::()
+ .unwrap();
+
+ let params: DepositRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ deposit::execute(
+ rpc_client,
+ config.evm_loader,
+ signer.as_ref(),
+ params.amount,
+ ¶ms.ether,
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/abi/emulate.rs b/evm_loader/lib/src/abi/emulate.rs
new file mode 100644
index 0000000000..f0259154a8
--- /dev/null
+++ b/evm_loader/lib/src/abi/emulate.rs
@@ -0,0 +1,31 @@
+use super::{params_to_neon_error, parse_emulation_params};
+use crate::commands::emulate::{self, EmulationResultWithAccounts};
+use crate::{types::request_models::EmulateRequestModel, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let params: EmulateRequestModel =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ let (token, chain, steps, accounts, solana_accounts) =
+ parse_emulation_params(config, context, ¶ms.emulation_params).await;
+
+ emulate::execute(
+ context.rpc_client,
+ config.evm_loader,
+ params.tx_params.into(),
+ token,
+ chain,
+ steps,
+ config.commitment,
+ &accounts,
+ &solana_accounts,
+ &None,
+ None,
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/abi/get_ether_account_data.rs b/evm_loader/lib/src/abi/get_ether_account_data.rs
new file mode 100644
index 0000000000..671421d6dc
--- /dev/null
+++ b/evm_loader/lib/src/abi/get_ether_account_data.rs
@@ -0,0 +1,15 @@
+use super::params_to_neon_error;
+use crate::commands::get_ether_account_data::{self, GetEtherAccountDataReturn};
+use crate::{types::request_models::GetEtherRequest, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let params: GetEtherRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ get_ether_account_data::execute(context.rpc_client, &config.evm_loader, ¶ms.ether).await
+}
diff --git a/evm_loader/lib/src/abi/get_neon_elf.rs b/evm_loader/lib/src/abi/get_neon_elf.rs
new file mode 100644
index 0000000000..3144be8fb1
--- /dev/null
+++ b/evm_loader/lib/src/abi/get_neon_elf.rs
@@ -0,0 +1,15 @@
+use super::params_to_neon_error;
+use crate::commands::get_neon_elf::{self, GetNeonElfReturn};
+use crate::{types::request_models::GetNeonElfRequest, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let params: GetNeonElfRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ get_neon_elf::execute(config, context, params.program_location.as_deref()).await
+}
diff --git a/evm_loader/lib/src/abi/get_storage_at.rs b/evm_loader/lib/src/abi/get_storage_at.rs
new file mode 100644
index 0000000000..fef01aec13
--- /dev/null
+++ b/evm_loader/lib/src/abi/get_storage_at.rs
@@ -0,0 +1,21 @@
+use super::params_to_neon_error;
+use crate::commands::get_storage_at::{self, GetStorageAtReturn};
+use crate::{types::request_models::GetStorageAtRequest, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let params: GetStorageAtRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ get_storage_at::execute(
+ context.rpc_client,
+ &config.evm_loader,
+ params.contract_id,
+ ¶ms.index,
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/abi/init_environment.rs b/evm_loader/lib/src/abi/init_environment.rs
new file mode 100644
index 0000000000..09734d667c
--- /dev/null
+++ b/evm_loader/lib/src/abi/init_environment.rs
@@ -0,0 +1,23 @@
+use super::params_to_neon_error;
+use crate::commands::init_environment::{self, InitEnvironmentReturn};
+use crate::{types::request_models::InitEnvironmentRequest, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(
+ context: &Context<'_>,
+ config: &Config,
+ params: &str,
+) -> NeonResult {
+ let params: InitEnvironmentRequest =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ init_environment::execute(
+ config,
+ context,
+ params.send_trx,
+ params.force,
+ params.keys_dir.as_deref(),
+ params.file.as_deref(),
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/abi/mod.rs b/evm_loader/lib/src/abi/mod.rs
new file mode 100644
index 0000000000..48ce9953aa
--- /dev/null
+++ b/evm_loader/lib/src/abi/mod.rs
@@ -0,0 +1,195 @@
+mod cancel_trx;
+mod collect_treasury;
+mod context;
+mod create_ether_account;
+mod deposit;
+mod emulate;
+mod get_ether_account_data;
+mod get_neon_elf;
+mod get_storage_at;
+mod init_environment;
+mod trace;
+
+use self::context::AbiContext;
+use crate::{
+ commands::get_neon_elf::CachedElfParams,
+ config::{self},
+ types::request_models::{EmulationParamsRequestModel, RequestWithSlot},
+ Config, Context, LibMethods, NeonError,
+};
+use abi_stable::{
+ prefix_type::WithMetadata,
+ sabi_extern_fn,
+ std_types::{RStr, RString},
+};
+use async_ffi::FutureExt;
+use evm_loader::types::Address;
+use lazy_static::lazy_static;
+use neon_lib_interface::{
+ types::{NeonEVMLibError, RNeonEVMLibResult},
+ NeonEVMLib,
+};
+use serde_json::json;
+use solana_sdk::pubkey::Pubkey;
+use std::str::FromStr;
+
+lazy_static! {
+ static ref RT: tokio::runtime::Runtime = tokio::runtime::Runtime::new().unwrap();
+}
+
+pub const _MODULE_WM_: &WithMetadata = &WithMetadata::new(NeonEVMLib {
+ hash,
+ get_version,
+ get_build_info,
+ invoke,
+});
+
+#[sabi_extern_fn]
+fn hash() -> RString {
+ env!("NEON_REVISION").into()
+}
+
+#[sabi_extern_fn]
+fn get_version() -> RString {
+ env!("CARGO_PKG_VERSION").into()
+}
+
+#[sabi_extern_fn]
+fn get_build_info() -> RString {
+ json!(crate::build_info::get_build_info())
+ .to_string()
+ .into()
+}
+
+#[sabi_extern_fn]
+fn invoke<'a>(method: RStr<'a>, params: RStr<'a>) -> RNeonEVMLibResult<'a> {
+ async move {
+ RT.block_on(dispatch(method.as_str(), params.as_str()))
+ .map(RString::from)
+ .map_err(neon_error_to_rstring)
+ .into()
+ }
+ .into_local_ffi()
+}
+
+async fn build_context() -> Result {
+ let api_options = config::load_api_config_from_enviroment();
+ let config = config::create_from_api_config(&api_options)?;
+
+ context::AbiContext::new(config)
+}
+
+async fn dispatch(method_str: &str, params_str: &str) -> Result {
+ let method: LibMethods = method_str.parse()?;
+ let abi_context = build_context().await?;
+ let RequestWithSlot {
+ slot,
+ tx_index_in_block,
+ } = serde_json::from_str(params_str).map_err(|_| params_to_neon_error(params_str))?;
+ let rpc_client = context::build_rpc_client(&abi_context, slot, tx_index_in_block).await?;
+ let config = &abi_context.config;
+ let context = crate::Context::new(rpc_client.as_ref(), config);
+
+ match method {
+ LibMethods::CreateEtherAccount => {
+ create_ether_account::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap())
+ }
+ LibMethods::CancelTrx => cancel_trx::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::CollectTreasury => collect_treasury::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::Deposit => deposit::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::Emulate => emulate::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::GetEtherAccountData => {
+ get_ether_account_data::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap())
+ }
+ LibMethods::GetNeonElf => get_neon_elf::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::GetStorageAt => get_storage_at::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::Trace => trace::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ LibMethods::InitEnvironment => init_environment::execute(&context, config, params_str)
+ .await
+ .map(|v| serde_json::to_string(&v).unwrap()),
+ // _ => Err(NeonError::IncorrectLibMethod),
+ }
+}
+
+fn params_to_neon_error(params: &str) -> NeonError {
+ NeonError::EnvironmentError(
+ crate::commands::init_environment::EnvironmentError::InvalidProgramParameter(params.into()),
+ )
+}
+
+fn neon_error_to_neon_lib_error(error: NeonError) -> NeonEVMLibError {
+ assert!(error.error_code() >= 0);
+ NeonEVMLibError {
+ code: error.error_code() as u32,
+ message: error.to_string(),
+ data: None,
+ }
+}
+
+fn neon_error_to_rstring(error: NeonError) -> RString {
+ RString::from(serde_json::to_string(&neon_error_to_neon_lib_error(error)).unwrap())
+}
+
+pub(crate) async fn parse_emulation_params(
+ config: &Config,
+ context: &Context<'_>,
+ params: &EmulationParamsRequestModel,
+) -> (Pubkey, u64, u64, Vec, Vec) {
+ // Read ELF params only if token_mint or chain_id is not set.
+ let mut token: Option = params.token_mint.map(Into::into);
+ let mut chain = params.chain_id;
+ if token.is_none() || chain.is_none() {
+ let cached_elf_params = CachedElfParams::new(config, context).await;
+ token = token.or_else(|| {
+ Some(
+ Pubkey::from_str(
+ cached_elf_params
+ .get("NEON_TOKEN_MINT")
+ .expect("NEON_TOKEN_MINT load error"),
+ )
+ .expect("NEON_TOKEN_MINT Pubkey ctor error "),
+ )
+ });
+ chain = chain.or_else(|| {
+ Some(
+ u64::from_str(
+ cached_elf_params
+ .get("NEON_CHAIN_ID")
+ .expect("NEON_CHAIN_ID load error"),
+ )
+ .expect("NEON_CHAIN_ID u64 ctor error"),
+ )
+ });
+ }
+ let token = token.expect("token_mint get error");
+ let chain = chain.expect("chain_id get error");
+ let max_steps = params.max_steps_to_execute;
+
+ let accounts = params.cached_accounts.clone().unwrap_or_default();
+
+ let solana_accounts = params
+ .solana_accounts
+ .clone()
+ .map(|vec| vec.into_iter().map(Into::into).collect())
+ .unwrap_or_default();
+
+ (token, chain, max_steps, accounts, solana_accounts)
+}
diff --git a/evm_loader/lib/src/abi/trace.rs b/evm_loader/lib/src/abi/trace.rs
new file mode 100644
index 0000000000..a243849b5b
--- /dev/null
+++ b/evm_loader/lib/src/abi/trace.rs
@@ -0,0 +1,28 @@
+use serde_json::Value;
+
+use super::{params_to_neon_error, parse_emulation_params};
+use crate::commands::trace::{self};
+use crate::{types::request_models::TraceRequestModel, NeonResult};
+use crate::{Config, Context};
+
+pub async fn execute(context: &Context<'_>, config: &Config, params: &str) -> NeonResult {
+ let params: TraceRequestModel =
+ serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?;
+
+ let (token, chain, steps, accounts, solana_accounts) =
+ parse_emulation_params(config, context, ¶ms.emulate_request.emulation_params).await;
+
+ trace::trace_transaction(
+ context.rpc_client,
+ config.evm_loader,
+ params.emulate_request.tx_params.into(),
+ token,
+ chain,
+ steps,
+ config.commitment,
+ &accounts,
+ &solana_accounts,
+ params.trace_call_config.unwrap_or_default(),
+ )
+ .await
+}
diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs
index d8c20a32ec..987bd5a5a0 100644
--- a/evm_loader/lib/src/errors.rs
+++ b/evm_loader/lib/src/errors.rs
@@ -4,6 +4,7 @@
use std::net::AddrParseError;
use log::error;
+use neon_lib_interface::NeonEVMLibLoadError;
use solana_cli::cli::CliError as SolanaCliError;
use solana_client::client_error::ClientError as SolanaClientError;
use solana_client::tpu_client::TpuSenderError as SolanaTpuSenderError;
@@ -42,6 +43,8 @@ pub enum NeonError {
/// EVM Loader Error
#[error("EVM Error. {0}")]
EvmError(#[from] evm_loader::error::Error),
+ #[error("Can't load db config")]
+ LoadingDBConfigError,
/// Need specify evm_loader
#[error("EVM loader must be specified.")]
EvmLoaderNotSpecified,
@@ -97,6 +100,12 @@ pub enum NeonError {
ClickHouse(ChError),
#[error("Slot {0} is less than earliest_rooted_slot={1}")]
EarlySlot(u64, u64),
+ #[error("library interface error")]
+ NeonEVMLibLoadError(#[from] NeonEVMLibLoadError),
+ #[error("Incorrect lib method")]
+ IncorrectLibMethod,
+ #[error("strum parse error {0:?}")]
+ StrumParseError(#[from] strum::ParseError),
}
impl NeonError {
@@ -132,6 +141,10 @@ impl NeonError {
NeonError::TxParametersParsingError(_) => 250,
NeonError::ClickHouse(_) => 252,
NeonError::EarlySlot(_, _) => 253,
+ NeonError::NeonEVMLibLoadError(_) => 254,
+ NeonError::LoadingDBConfigError => 255,
+ NeonError::IncorrectLibMethod => 256,
+ NeonError::StrumParseError(_) => 257,
}
}
}
diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs
index 7475b056c4..a7466f24cc 100644
--- a/evm_loader/lib/src/lib.rs
+++ b/evm_loader/lib/src/lib.rs
@@ -1,3 +1,4 @@
+mod abi;
pub mod account_storage;
pub mod build_info;
pub mod build_info_common;
@@ -9,8 +10,44 @@ pub mod rpc;
pub mod syscall_stubs;
pub mod types;
+use abi::_MODULE_WM_;
+use abi_stable::export_root_module;
pub use config::Config;
pub use context::Context;
pub use errors::NeonError;
+use neon_lib_interface::NeonEVMLib_Ref;
pub type NeonResult = Result;
+
+const MODULE: NeonEVMLib_Ref = NeonEVMLib_Ref(_MODULE_WM_.static_as_prefix());
+
+#[export_root_module]
+pub fn get_root_module() -> NeonEVMLib_Ref {
+ MODULE
+}
+
+use strum_macros::{AsRefStr, Display, EnumString, IntoStaticStr};
+
+#[derive(Debug, Clone, Copy, PartialEq, Display, EnumString, IntoStaticStr, AsRefStr)]
+pub enum LibMethods {
+ #[strum(serialize = "emulate")]
+ Emulate,
+ #[strum(serialize = "get_ether_account_data")]
+ GetEtherAccountData,
+ #[strum(serialize = "get_storage_at")]
+ GetStorageAt,
+ #[strum(serialize = "trace")]
+ Trace,
+ #[strum(serialize = "cancel_trx")]
+ CancelTrx,
+ #[strum(serialize = "collect_treasury")]
+ CollectTreasury,
+ #[strum(serialize = "create_ether_account")]
+ CreateEtherAccount,
+ #[strum(serialize = "deposit")]
+ Deposit,
+ #[strum(serialize = "get_neon_elf")]
+ GetNeonElf,
+ #[strum(serialize = "init_environment")]
+ InitEnvironment,
+}
diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs
index 54cdb2db9c..b3a5becd02 100644
--- a/evm_loader/lib/src/types/request_models.rs
+++ b/evm_loader/lib/src/types/request_models.rs
@@ -15,6 +15,28 @@ pub struct GetEtherRequest {
pub slot: Option,
}
+#[derive(Deserialize, Serialize, Debug, Default)]
+pub struct RequestWithSlot {
+ pub slot: Option,
+ pub tx_index_in_block: Option,
+}
+
+#[derive(Deserialize, Serialize, Debug, Default)]
+pub struct CreateEtherAccountRequest {
+ pub ether: Address,
+}
+
+#[derive(Deserialize, Serialize, Debug, Default)]
+pub struct DepositRequest {
+ pub ether: Address,
+ pub amount: u64,
+}
+
+#[derive(Deserialize, Serialize, Debug, Default)]
+pub struct GetNeonElfRequest {
+ pub program_location: Option,
+}
+
#[derive(Deserialize, Serialize, Debug, Default)]
pub struct GetStorageAtRequest {
pub contract_id: Address,
@@ -22,6 +44,19 @@ pub struct GetStorageAtRequest {
pub slot: Option,
}
+#[derive(Deserialize, Serialize, Debug, Default)]
+pub struct CancelTrxRequest {
+ pub storage_account: Pubkey,
+}
+
+#[derive(Deserialize, Serialize, Debug, Default)]
+pub struct InitEnvironmentRequest {
+ pub send_trx: bool,
+ pub force: bool,
+ pub keys_dir: Option,
+ pub file: Option,
+}
+
#[derive(Deserialize, Serialize, Default)]
pub struct TxParamsRequestModel {
pub sender: Address,
diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml
new file mode 100644
index 0000000000..826081a554
--- /dev/null
+++ b/evm_loader/rpc-client/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "neon-rpc-client"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+serde = "1.0.189"
+serde_json = "1.0.107"
+jsonrpc-v2 = "0.13.0"
+neon-lib = { path = "../lib" }
+thiserror = "1.0.49"
+async-trait = "0.1.74"
+jsonrpsee-core = "0.20.2"
+jsonrpsee-http-client = "0.20.2"
+jsonrpsee-types = "0.20.2"
+tokio = { version = "1", features = ["full"] }
+build-info = { version = "0.0.31", features = ["serde"] }
diff --git a/evm_loader/rpc-client/src/config.rs b/evm_loader/rpc-client/src/config.rs
new file mode 100644
index 0000000000..41a62c1fe4
--- /dev/null
+++ b/evm_loader/rpc-client/src/config.rs
@@ -0,0 +1,9 @@
+pub struct NeonRpcClientConfig {
+ pub url: String,
+}
+
+impl NeonRpcClientConfig {
+ pub fn new(url: impl Into) -> NeonRpcClientConfig {
+ NeonRpcClientConfig { url: url.into() }
+ }
+}
diff --git a/evm_loader/rpc-client/src/error.rs b/evm_loader/rpc-client/src/error.rs
new file mode 100644
index 0000000000..2f6564fe32
--- /dev/null
+++ b/evm_loader/rpc-client/src/error.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+pub enum NeonRpcClientError {
+ #[error("Jsonrpc error. {0:?}")]
+ JsonrpseeError(#[from] jsonrpsee_core::Error),
+ #[error("serde json error. {0:?}")]
+ SerdeJsonError(#[from] serde_json::Error),
+}
diff --git a/evm_loader/rpc-client/src/http.rs b/evm_loader/rpc-client/src/http.rs
new file mode 100644
index 0000000000..cc220774ab
--- /dev/null
+++ b/evm_loader/rpc-client/src/http.rs
@@ -0,0 +1,135 @@
+use async_trait::async_trait;
+use jsonrpsee_core::{client::ClientT, rpc_params};
+use jsonrpsee_http_client::{HttpClient, HttpClientBuilder};
+use neon_lib::LibMethods;
+use neon_lib::{
+ commands::{
+ cancel_trx::CancelTrxReturn, collect_treasury::CollectTreasuryReturn,
+ create_ether_account::CreateEtherAccountReturn, deposit::DepositReturn,
+ emulate::EmulationResultWithAccounts, get_ether_account_data::GetEtherAccountDataReturn,
+ get_neon_elf::GetNeonElfReturn, get_storage_at::GetStorageAtReturn,
+ init_environment::InitEnvironmentReturn,
+ },
+ types::request_models::{
+ CancelTrxRequest, CreateEtherAccountRequest, DepositRequest, EmulateRequestModel,
+ GetEtherRequest, GetNeonElfRequest, GetStorageAtRequest, InitEnvironmentRequest,
+ TraceRequestModel,
+ },
+};
+use serde::de::DeserializeOwned;
+use serde::Serialize;
+
+use crate::{config::NeonRpcClientConfig, NeonRpcClient, NeonRpcClientResult};
+
+pub struct NeonRpcHttpClient {
+ client: HttpClient,
+}
+
+impl NeonRpcHttpClient {
+ pub async fn new(config: NeonRpcClientConfig) -> NeonRpcClientResult {
+ Ok(NeonRpcHttpClient {
+ client: HttpClientBuilder::default().build(config.url)?,
+ })
+ }
+}
+
+pub struct NeonRpcHttpClientBuilder {}
+
+impl NeonRpcHttpClientBuilder {
+ pub fn new() -> NeonRpcHttpClientBuilder {
+ NeonRpcHttpClientBuilder {}
+ }
+
+ pub async fn build(&self, url: impl Into) -> NeonRpcClientResult {
+ let config = NeonRpcClientConfig::new(url);
+ NeonRpcHttpClient::new(config).await
+ }
+}
+
+impl Default for NeonRpcHttpClientBuilder {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[async_trait(?Send)]
+impl NeonRpcClient for NeonRpcHttpClient {
+ async fn cancel_trx(&self, params: CancelTrxRequest) -> NeonRpcClientResult {
+ self.request(LibMethods::CancelTrx, params).await
+ }
+
+ async fn collect_treasury(&self) -> NeonRpcClientResult {
+ self.request_without_params(LibMethods::CollectTreasury)
+ .await
+ }
+
+ async fn create_ether_account(
+ &self,
+ params: CreateEtherAccountRequest,
+ ) -> NeonRpcClientResult {
+ self.request(LibMethods::CreateEtherAccount, params).await
+ }
+
+ async fn deposit(&self, params: DepositRequest) -> NeonRpcClientResult {
+ self.request(LibMethods::Deposit, params).await
+ }
+
+ async fn emulate(
+ &self,
+ params: EmulateRequestModel,
+ ) -> NeonRpcClientResult {
+ self.request(LibMethods::Emulate, params).await
+ }
+
+ async fn get_ether_account_data(
+ &self,
+ params: GetEtherRequest,
+ ) -> NeonRpcClientResult {
+ self.request(LibMethods::GetEtherAccountData, params).await
+ }
+
+ async fn get_neon_elf(
+ &self,
+ params: GetNeonElfRequest,
+ ) -> NeonRpcClientResult {
+ self.request(LibMethods::GetNeonElf, params).await
+ }
+
+ async fn get_storage_at(
+ &self,
+ params: GetStorageAtRequest,
+ ) -> NeonRpcClientResult {
+ self.request(LibMethods::GetStorageAt, params).await
+ }
+
+ async fn init_environment(
+ &self,
+ params: InitEnvironmentRequest,
+ ) -> NeonRpcClientResult {
+ self.request(LibMethods::InitEnvironment, params).await
+ }
+
+ async fn trace(&self, params: TraceRequestModel) -> NeonRpcClientResult {
+ self.request(LibMethods::Trace, params).await
+ }
+}
+
+impl NeonRpcHttpClient {
+ async fn request(&self, method: LibMethods, params: P) -> NeonRpcClientResult
+ where
+ P: Serialize,
+ R: DeserializeOwned,
+ {
+ Ok(self
+ .client
+ .request(method.into(), rpc_params![params])
+ .await?)
+ }
+
+ async fn request_without_params(&self, method: LibMethods) -> NeonRpcClientResult
+ where
+ R: jsonrpsee_core::DeserializeOwned,
+ {
+ Ok(self.client.request(method.into(), rpc_params![]).await?)
+ }
+}
diff --git a/evm_loader/rpc-client/src/lib.rs b/evm_loader/rpc-client/src/lib.rs
new file mode 100644
index 0000000000..e761c491cf
--- /dev/null
+++ b/evm_loader/rpc-client/src/lib.rs
@@ -0,0 +1,55 @@
+mod config;
+mod error;
+pub mod http;
+
+pub use error::NeonRpcClientError;
+
+use async_trait::async_trait;
+use neon_lib::{
+ commands::{
+ cancel_trx::CancelTrxReturn, collect_treasury::CollectTreasuryReturn,
+ create_ether_account::CreateEtherAccountReturn, deposit::DepositReturn,
+ emulate::EmulationResultWithAccounts, get_ether_account_data::GetEtherAccountDataReturn,
+ get_neon_elf::GetNeonElfReturn, get_storage_at::GetStorageAtReturn,
+ init_environment::InitEnvironmentReturn,
+ },
+ types::request_models::{
+ CancelTrxRequest, CreateEtherAccountRequest, DepositRequest, EmulateRequestModel,
+ GetEtherRequest, GetNeonElfRequest, GetStorageAtRequest, InitEnvironmentRequest,
+ TraceRequestModel,
+ },
+};
+
+type NeonRpcClientResult = Result;
+
+#[async_trait(?Send)]
+pub trait NeonRpcClient {
+ async fn cancel_trx(&self, params: CancelTrxRequest) -> NeonRpcClientResult;
+ async fn collect_treasury(&self) -> NeonRpcClientResult;
+ async fn create_ether_account(
+ &self,
+ params: CreateEtherAccountRequest,
+ ) -> NeonRpcClientResult;
+ async fn deposit(&self, params: DepositRequest) -> NeonRpcClientResult;
+ async fn emulate(
+ &self,
+ params: EmulateRequestModel,
+ ) -> NeonRpcClientResult;
+ async fn get_ether_account_data(
+ &self,
+ params: GetEtherRequest,
+ ) -> NeonRpcClientResult;
+ async fn get_neon_elf(
+ &self,
+ params: GetNeonElfRequest,
+ ) -> NeonRpcClientResult;
+ async fn get_storage_at(
+ &self,
+ params: GetStorageAtRequest,
+ ) -> NeonRpcClientResult;
+ async fn init_environment(
+ &self,
+ params: InitEnvironmentRequest,
+ ) -> NeonRpcClientResult;
+ async fn trace(&self, params: TraceRequestModel) -> NeonRpcClientResult;
+}
diff --git a/evm_loader/rpc/.gitignore b/evm_loader/rpc/.gitignore
new file mode 100644
index 0000000000..e824517975
--- /dev/null
+++ b/evm_loader/rpc/.gitignore
@@ -0,0 +1,3 @@
+libs
+d
+keys
\ No newline at end of file
diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml
new file mode 100644
index 0000000000..ea03ce5dc6
--- /dev/null
+++ b/evm_loader/rpc/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "neon-rpc"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+actix-web = "4.3.1"
+clap = "2.33.3"
+jsonrpc-v2 = "0.13.0"
+neon-lib-interface = { path = "../lib-interface" }
+neon-lib = { path = "../lib" }
+semver = "1.0.18"
+serde = "1.0.188"
+serde_json = "1.0.107"
+tokio = { version = "1", features = ["full"] }
+build-info = { version = "0.0.31", features = ["serde"] }
+thiserror = "1.0"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+tracing-appender = "0.2.2"
+
+[build-dependencies]
+build-info-build = "0.0.31"
diff --git a/evm_loader/rpc/build.rs b/evm_loader/rpc/build.rs
new file mode 100644
index 0000000000..d36778f606
--- /dev/null
+++ b/evm_loader/rpc/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ build_info_build::build_script();
+}
diff --git a/evm_loader/rpc/src/build_info.rs b/evm_loader/rpc/src/build_info.rs
new file mode 100644
index 0000000000..85f42da0df
--- /dev/null
+++ b/evm_loader/rpc/src/build_info.rs
@@ -0,0 +1,7 @@
+use neon_lib::build_info_common::SlimBuildInfo;
+
+build_info::build_info!(fn build_info);
+
+pub fn get_build_info() -> SlimBuildInfo {
+ build_info().into()
+}
diff --git a/evm_loader/rpc/src/context.rs b/evm_loader/rpc/src/context.rs
new file mode 100644
index 0000000000..614b629a54
--- /dev/null
+++ b/evm_loader/rpc/src/context.rs
@@ -0,0 +1,6 @@
+use neon_lib_interface::NeonEVMLib_Ref;
+use std::collections::HashMap;
+
+pub struct Context {
+ pub libraries: HashMap,
+}
diff --git a/evm_loader/rpc/src/error.rs b/evm_loader/rpc/src/error.rs
new file mode 100644
index 0000000000..bc7f2818f2
--- /dev/null
+++ b/evm_loader/rpc/src/error.rs
@@ -0,0 +1,27 @@
+use neon_lib::errors::NeonError;
+use neon_lib_interface::NeonEVMLibLoadError;
+use std::net::AddrParseError;
+
+use thiserror::Error;
+
+#[allow(clippy::enum_variant_names)]
+#[derive(Debug, Error)]
+pub enum NeonRPCError {
+ /// Std IO Error
+ #[error("Std I/O error. {0:?}")]
+ StdIoError(#[from] std::io::Error),
+ #[error("Addr parse error. {0:?}")]
+ AddrParseError(#[from] AddrParseError),
+ #[error("Neon error. {0:?}")]
+ NeonError(#[from] NeonError),
+ #[error("Neon lib error. {0:?}")]
+ NeonEVMLibLoadError(#[from] NeonEVMLibLoadError),
+ #[error("Neon RPC: Incorrect parameters.")]
+ IncorrectParameters(),
+}
+
+impl From for jsonrpc_v2::Error {
+ fn from(value: NeonRPCError) -> Self {
+ jsonrpc_v2::Error::internal(value)
+ }
+}
diff --git a/evm_loader/rpc/src/handlers/cancel_trx.rs b/evm_loader/rpc/src/handlers/cancel_trx.rs
new file mode 100644
index 0000000000..8a24720d06
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/cancel_trx.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::CancelTrxRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::CancelTrx,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/collect_treasury.rs b/evm_loader/rpc/src/handlers/collect_treasury.rs
new file mode 100644
index 0000000000..967e41fc93
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/collect_treasury.rs
@@ -0,0 +1,13 @@
+use super::invoke;
+use crate::context::Context;
+use jsonrpc_v2::Data;
+use neon_lib::LibMethods;
+
+pub async fn handle(ctx: Data) -> Result {
+ invoke(
+ LibMethods::CollectTreasury,
+ ctx,
+ serde_json::value::to_value("null").unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/create_ether_account.rs b/evm_loader/rpc/src/handlers/create_ether_account.rs
new file mode 100644
index 0000000000..3641baacd3
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/create_ether_account.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::CreateEtherAccountRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::CreateEtherAccount,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/deposit.rs b/evm_loader/rpc/src/handlers/deposit.rs
new file mode 100644
index 0000000000..8f728eaf96
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/deposit.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::DepositRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::Deposit,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/emulate.rs b/evm_loader/rpc/src/handlers/emulate.rs
new file mode 100644
index 0000000000..08636a281e
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/emulate.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::EmulateRequestModel, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::Emulate,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/get_ether_account_data.rs b/evm_loader/rpc/src/handlers/get_ether_account_data.rs
new file mode 100644
index 0000000000..fedc9fc92c
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/get_ether_account_data.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::GetEtherRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::GetEtherAccountData,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/get_neon_elf.rs b/evm_loader/rpc/src/handlers/get_neon_elf.rs
new file mode 100644
index 0000000000..9c5d6b5e15
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/get_neon_elf.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::GetNeonElfRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::GetNeonElf,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/get_storage_at.rs b/evm_loader/rpc/src/handlers/get_storage_at.rs
new file mode 100644
index 0000000000..1a79c6cbff
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/get_storage_at.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::GetStorageAtRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::GetStorageAt,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/info.rs b/evm_loader/rpc/src/handlers/info.rs
new file mode 100644
index 0000000000..afc36bb762
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/info.rs
@@ -0,0 +1,7 @@
+use serde_json::json;
+
+use crate::build_info::get_build_info;
+
+pub async fn handle() -> Result {
+ Ok(json!(get_build_info()))
+}
diff --git a/evm_loader/rpc/src/handlers/init_environment.rs b/evm_loader/rpc/src/handlers/init_environment.rs
new file mode 100644
index 0000000000..f41d49d035
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/init_environment.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::InitEnvironmentRequest, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::InitEnvironment,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/handlers/mod.rs b/evm_loader/rpc/src/handlers/mod.rs
new file mode 100644
index 0000000000..1d657e1264
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/mod.rs
@@ -0,0 +1,71 @@
+pub mod cancel_trx;
+pub mod collect_treasury;
+pub mod create_ether_account;
+pub mod deposit;
+pub mod emulate;
+pub mod get_ether_account_data;
+pub mod get_neon_elf;
+pub mod get_storage_at;
+pub mod info;
+pub mod init_environment;
+pub mod trace;
+
+use crate::context::Context;
+use jsonrpc_v2::Data;
+use neon_lib::LibMethods;
+use serde_json::Value;
+
+pub async fn invoke(
+ method: LibMethods,
+ context: Data,
+ params: serde_json::Value,
+) -> Result {
+ // just for testing
+ let hash = context
+ .libraries
+ .keys()
+ .last()
+ .ok_or(jsonrpc_v2::Error::internal("library collection is empty"))?;
+
+ let library = context
+ .libraries
+ .get(hash)
+ .ok_or(jsonrpc_v2::Error::internal(format!(
+ "Library not found for hash {hash}"
+ )))?;
+
+ tracing::debug!("ver {:?}", library.hash()());
+
+ let method_str: &str = method.into();
+
+ let result: Result<_, _> = library.invoke()(
+ method_str.into(),
+ serde_json::to_string(¶ms).unwrap().as_str().into(),
+ )
+ .await
+ .map(|x| serde_json::from_str::(&x).unwrap())
+ .map_err(String::from)
+ .into();
+
+ result.map_err(|s: String| {
+ let val: Value = serde_json::from_str(s.as_str()).unwrap();
+ let code = val
+ .get("code")
+ .and_then(|value| value.as_i64())
+ .unwrap_or(0);
+ let message = val
+ .get("message")
+ .and_then(|value| value.as_str())
+ .unwrap_or("");
+ let data = val
+ .get("data")
+ .and_then(|value| value.as_str())
+ .unwrap_or("null");
+
+ jsonrpc_v2::Error::Full {
+ code,
+ message: message.to_string(),
+ data: Some(Box::new(data.to_string())),
+ }
+ })
+}
diff --git a/evm_loader/rpc/src/handlers/trace.rs b/evm_loader/rpc/src/handlers/trace.rs
new file mode 100644
index 0000000000..372223c538
--- /dev/null
+++ b/evm_loader/rpc/src/handlers/trace.rs
@@ -0,0 +1,17 @@
+use super::invoke;
+use crate::{context::Context, error::NeonRPCError};
+use jsonrpc_v2::{Data, Params};
+use neon_lib::{types::request_models::TraceRequestModel, LibMethods};
+
+pub async fn handle(
+ ctx: Data,
+ Params(params): Params>,
+) -> Result {
+ let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?;
+ invoke(
+ LibMethods::Trace,
+ ctx,
+ serde_json::value::to_value(param).unwrap(),
+ )
+ .await
+}
diff --git a/evm_loader/rpc/src/main.rs b/evm_loader/rpc/src/main.rs
new file mode 100644
index 0000000000..40cd98080f
--- /dev/null
+++ b/evm_loader/rpc/src/main.rs
@@ -0,0 +1,76 @@
+// use std::{collections::HashMap, error::Error};
+mod build_info;
+mod context;
+mod error;
+mod handlers;
+mod options;
+mod rpc;
+
+use crate::build_info::get_build_info;
+use context::Context;
+use error::NeonRPCError;
+use neon_lib::config;
+use std::{env, net::SocketAddr, str::FromStr};
+use tracing::info;
+use tracing_appender::non_blocking::NonBlockingBuilder;
+
+type NeonRPCResult = Result;
+
+#[actix_web::main]
+async fn main() -> NeonRPCResult<()> {
+ let matches = options::parse();
+
+ // initialize tracing
+ let (non_blocking, _guard) = NonBlockingBuilder::default()
+ .lossy(false)
+ .finish(std::io::stdout());
+
+ tracing_subscriber::fmt().with_writer(non_blocking).init();
+
+ let lib_dir = matches.value_of("LIB-DIR").unwrap();
+ let libraries = neon_lib_interface::load_libraries(lib_dir)?;
+
+ info!("BUILD INFO: {}", get_build_info());
+ info!(
+ "LIBRARY DIR: {}, count: {}",
+ lib_dir,
+ libraries.keys().len(),
+ );
+
+ if libraries.keys().len() > 0 {
+ info!("=== LIBRARY VERSIONS: =================================================================");
+ for library_ver in libraries.keys() {
+ info!("Lib version: {}", library_ver);
+ }
+ info!("=== END LIBRARY VERSIONS ==============================================================");
+ }
+
+ // check configs
+ let api_config = config::load_api_config_from_enviroment();
+ let _ = config::create_from_api_config(&api_config)?;
+
+ let ctx = Context { libraries };
+ let rpc = rpc::build_rpc(ctx)?;
+
+ let listener_addr = matches
+ .value_of("host")
+ .map(std::borrow::ToOwned::to_owned)
+ .or_else(|| Some(env::var("NEON_API_LISTENER_ADDR").unwrap_or("0.0.0.0:3100".to_owned())))
+ .unwrap();
+
+ let addr = SocketAddr::from_str(listener_addr.as_str())?;
+
+ actix_web::HttpServer::new(move || {
+ let rpc = rpc.clone();
+ actix_web::App::new().service(
+ actix_web::web::service("/")
+ .guard(actix_web::guard::Post())
+ .finish(rpc.into_web_service()),
+ )
+ })
+ .bind(addr)?
+ .run()
+ .await?;
+
+ Ok(())
+}
diff --git a/evm_loader/rpc/src/options.rs b/evm_loader/rpc/src/options.rs
new file mode 100644
index 0000000000..c7d953ce4a
--- /dev/null
+++ b/evm_loader/rpc/src/options.rs
@@ -0,0 +1,26 @@
+use clap::ArgMatches;
+
+pub fn parse<'a>() -> ArgMatches<'a> {
+ clap::App::new("Neon Core RPC")
+ .version(env!("CARGO_PKG_VERSION"))
+ .author("Neon Labs")
+ .about("Runs a Neon Core RPC server")
+ .arg(
+ clap::Arg::with_name("LIB-DIR")
+ .env("NEON_LIB_DIR")
+ .alias("dir")
+ .help("Directory with neon libraries to load")
+ .required(true)
+ .index(1),
+ )
+ .arg(
+ clap::Arg::with_name("HOST")
+ .alias("host")
+ .env("NEON_API_LISTENER_ADDR")
+ .default_value("0.0.0.0:3100")
+ .help("RPC host to connect to")
+ .required(false)
+ .index(2),
+ )
+ .get_matches()
+}
diff --git a/evm_loader/rpc/src/rpc.rs b/evm_loader/rpc/src/rpc.rs
new file mode 100644
index 0000000000..45ce4f66b5
--- /dev/null
+++ b/evm_loader/rpc/src/rpc.rs
@@ -0,0 +1,47 @@
+use crate::error::NeonRPCError;
+use crate::handlers::{
+ cancel_trx, collect_treasury, create_ether_account, deposit, get_neon_elf, get_storage_at,
+ info, init_environment,
+};
+use crate::{
+ context::Context,
+ handlers::{emulate, get_ether_account_data, trace},
+};
+
+use jsonrpc_v2::{Data, MapRouter, Server};
+use neon_lib::LibMethods;
+use std::sync::Arc;
+
+pub fn build_rpc(ctx: Context) -> Result>, NeonRPCError> {
+ let mut rpc_builder = Server::new().with_data(Data::new(ctx));
+
+ rpc_builder = rpc_builder.with_method("build_info", info::handle);
+
+ rpc_builder = rpc_builder.with_method(
+ LibMethods::GetEtherAccountData.to_string(),
+ get_ether_account_data::handle,
+ );
+ rpc_builder =
+ rpc_builder.with_method(LibMethods::GetStorageAt.to_string(), get_storage_at::handle);
+ rpc_builder = rpc_builder.with_method(LibMethods::Trace.to_string(), trace::handle);
+ rpc_builder = rpc_builder.with_method(LibMethods::Emulate.to_string(), emulate::handle);
+ rpc_builder = rpc_builder.with_method(LibMethods::CancelTrx.to_string(), cancel_trx::handle);
+ rpc_builder = rpc_builder.with_method(
+ LibMethods::CollectTreasury.to_string(),
+ collect_treasury::handle,
+ );
+ rpc_builder = rpc_builder.with_method(
+ LibMethods::CreateEtherAccount.to_string(),
+ create_ether_account::handle,
+ );
+ rpc_builder = rpc_builder.with_method(LibMethods::Deposit.to_string(), deposit::handle);
+ rpc_builder = rpc_builder.with_method(LibMethods::GetNeonElf.to_string(), get_neon_elf::handle);
+ rpc_builder = rpc_builder.with_method(
+ LibMethods::InitEnvironment.to_string(),
+ init_environment::handle,
+ );
+
+ let rpc = rpc_builder.finish();
+
+ Ok(rpc)
+}