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) +}