diff --git a/.dockerignore b/.dockerignore index c51436d7..24acb01f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,18 @@ +# Generated by Cargo, executables +target + +# GitHub workflows/actions .github + +# Documentation docs + +# Dockerfile Dockerfile + +# Folder containing files for bundler spec tests bundler-spec-tests -target + +# Third party dependencies crates/contracts/thirdparty/account-abstraction/* tests/thirdparty/bundler/* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51762491..7cb81ac4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,13 +19,18 @@ jobs: sudo rm -rf /opt/ghc sudo rm -rf "/usr/local/share/boost" sudo rm -rf "$AGENT_TOOLSDIRECTORY" + - uses: actions/checkout@v2 - - name: Setup Rust toolchain - uses: actions-rs/toolchain@v1 + - name: Setup Rust toolchain (stable) + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - name: Setup Rust toolchain (nightly) + uses: dtolnay/rust-toolchain@nightly with: - toolchain: stable - components: rustfmt, clippy + components: rustfmt - name: Install cargo tools run: | @@ -100,6 +105,7 @@ jobs: repository: eth-infinitism/bundler-spec-tests ref: 'b9f192f39298e6586729d40f29e3098c92e5c0b9' submodules: true + - uses: actions/checkout@v3 with: path: diff --git a/.gitignore b/.gitignore index 2cf2f13b..b9163b31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,12 @@ +# Generated by Cargo, executables /target -.local + +# IDE .vscode + +# Node directories +.local + +# env files **/.env .env -db \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..30879266 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @Vid201 @zsluedem \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 5f8278af..d792207e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + [[package]] name = "aes" version = "0.7.5" @@ -66,11 +76,25 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ - "aead", + "aead 0.4.3", "aes 0.7.5", "cipher 0.3.0", "ctr 0.8.0", - "ghash", + "ghash 0.4.4", + "subtle", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead 0.5.2", + "aes 0.8.3", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.0", "subtle", ] @@ -282,7 +306,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -292,7 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -502,22 +526,21 @@ checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" [[package]] name = "async-io" -version = "1.13.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7" dependencies = [ - "async-lock", - "autocfg", + "async-lock 3.2.0", "cfg-if", "concurrent-queue", + "futures-io", "futures-lite", - "log", "parking", "polling", - "rustix 0.37.27", + "rustix", "slab", - "socket2 0.4.10", - "waker-fn", + "tracing", + "windows-sys 0.52.0", ] [[package]] @@ -526,7 +549,18 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c" +dependencies = [ + "event-listener 4.0.1", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -599,9 +633,9 @@ dependencies = [ [[package]] name = "atomic-polyfill" -version = "0.1.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" dependencies = [ "critical-section", ] @@ -876,9 +910,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", "serde", @@ -997,25 +1031,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher 0.4.4", "cpufeatures", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "aead", + "aead 0.5.2", "chacha20", - "cipher 0.3.0", + "cipher 0.4.4", "poly1305", "zeroize", ] @@ -1032,7 +1065,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1052,6 +1085,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1184,9 +1218,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] @@ -1276,9 +1310,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -1353,6 +1387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -1616,7 +1651,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1637,7 +1672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98c05fa26996c6141f78ac4fafbe297a7fa69690565ba4e0d1f2e60bde5ce501" dependencies = [ "aes 0.7.5", - "aes-gcm", + "aes-gcm 0.9.4", "arrayvec", "delay_map", "enr", @@ -1881,9 +1916,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -1905,7 +1940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2001,7 +2036,7 @@ checksum = "9ba3fd516c15a9a587135229466dbbfc85796de55c5660afbbb1b1c78517d85c" dependencies = [ "ethers-addressbook 2.0.10", "ethers-contract 2.0.10", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "ethers-etherscan 2.0.10", "ethers-middleware 2.0.10", "ethers-providers 2.0.10", @@ -2026,7 +2061,7 @@ version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6e9e8acd0ed348403cc73a670c24daba3226c40b98dc1a41903766b3ab6240a" dependencies = [ - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "once_cell", "serde", "serde_json", @@ -2060,7 +2095,7 @@ dependencies = [ "const-hex", "ethers-contract-abigen 2.0.10", "ethers-contract-derive 2.0.10", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "ethers-providers 2.0.10", "futures-util", "once_cell", @@ -2102,7 +2137,7 @@ dependencies = [ "Inflector", "const-hex", "dunce", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "ethers-etherscan 2.0.10", "eyre", "prettyplease 0.2.15", @@ -2141,7 +2176,7 @@ dependencies = [ "Inflector", "const-hex", "ethers-contract-abigen 2.0.10", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "proc-macro2", "quote", "serde_json", @@ -2209,8 +2244,8 @@ dependencies = [ [[package]] name = "ethers-core" -version = "2.0.10" -source = "git+https://github.com/gakonst/ethers-rs#17c008e915f22686bfdc769e7140e8c50e6b8a61" +version = "2.0.11" +source = "git+https://github.com/gakonst/ethers-rs#40cc8cc54f7d36aa24147c937772600e5b119399" dependencies = [ "arrayvec", "bytes", @@ -2253,7 +2288,7 @@ version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e53451ea4a8128fbce33966da71132cf9e1040dcfd2a2084fd7733ada7b2045" dependencies = [ - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "reqwest", "semver 1.0.20", "serde", @@ -2333,7 +2368,7 @@ dependencies = [ "async-trait", "auto_impl", "ethers-contract 2.0.10", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "ethers-etherscan 2.0.10", "ethers-providers 2.0.10", "ethers-signers 2.0.10", @@ -2401,7 +2436,7 @@ dependencies = [ "bytes", "const-hex", "enr", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "futures-core", "futures-timer", "futures-util", @@ -2456,7 +2491,7 @@ dependencies = [ "const-hex", "elliptic-curve", "eth-keystore", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "rand 0.8.5", "sha2 0.10.8", "thiserror", @@ -2507,7 +2542,7 @@ dependencies = [ "const-hex", "dirs 5.0.1", "dunce", - "ethers-core 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-core 2.0.10", "glob", "home", "md-5", @@ -2535,6 +2570,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f2cdcf274580f2d63697192d744727b3198894b1bf02923643bf59e2c26712" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.1", + "pin-project-lite", +] + [[package]] name = "examples-simple-account" version = "0.3.0-alpha" @@ -2562,8 +2618,8 @@ dependencies = [ "futures", "parking_lot 0.12.1", "silius-contracts", + "silius-mempool", "silius-primitives", - "silius-uopool", "tempdir", "tokio", ] @@ -2599,15 +2655,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.0.1" @@ -2792,17 +2839,12 @@ checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-lite" -version = "1.13.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143" dependencies = [ - "fastrand 1.9.0", "futures-core", - "futures-io", - "memchr", - "parking", "pin-project-lite", - "waker-fn", ] [[package]] @@ -2925,7 +2967,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug", - "polyval", + "polyval 0.5.3", +] + +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug", + "polyval 0.6.1", ] [[package]] @@ -2964,15 +3016,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -3157,9 +3209,9 @@ dependencies = [ [[package]] name = "heapless" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ "atomic-polyfill", "hash32", @@ -3253,7 +3305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3430,19 +3482,19 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "if-watch" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb892e5777fe09e16f3d44de7802f4daa7267ecbe8c466f19d94e25bb0c303e" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ "async-io", "core-foundation", @@ -3560,17 +3612,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - [[package]] name = "ipconfig" version = "0.3.2" @@ -3579,7 +3620,7 @@ checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ "socket2 0.5.5", "widestring", - "windows-sys", + "windows-sys 0.48.0", "winreg", ] @@ -3596,8 +3637,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.21", - "windows-sys", + "rustix", + "windows-sys 0.48.0", ] [[package]] @@ -3720,7 +3761,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64c6832a55f662b5a6ecc844db24b8b9c387453f923de863062c60ce33d62b81" dependencies = [ "anyhow", - "async-lock", + "async-lock 2.8.0", "async-trait", "beef", "futures-timer", @@ -3748,7 +3789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" dependencies = [ "anyhow", - "async-lock", + "async-lock 2.8.0", "async-trait", "beef", "futures-timer", @@ -4212,7 +4253,7 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "log", - "lru 0.12.0", + "lru 0.12.1", "quick-protobuf", "quick-protobuf-codec", "smallvec 1.11.1", @@ -4518,12 +4559,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -4566,9 +4601,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" +checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7" dependencies = [ "hashbrown 0.14.2", ] @@ -4691,7 +4726,7 @@ checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -5185,7 +5220,7 @@ dependencies = [ "libc", "redox_syscall 0.4.1", "smallvec 1.11.1", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -5401,29 +5436,27 @@ checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" [[package]] name = "polling" -version = "2.8.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" dependencies = [ - "autocfg", - "bitflags 1.3.2", "cfg-if", "concurrent-queue", - "libc", - "log", "pin-project-lite", - "windows-sys", + "rustix", + "tracing", + "windows-sys 0.52.0", ] [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug", - "universal-hash", + "universal-hash 0.5.1", ] [[package]] @@ -5435,7 +5468,19 @@ dependencies = [ "cfg-if", "cpufeatures", "opaque-debug", - "universal-hash", + "universal-hash 0.4.1", +] + +[[package]] +name = "polyval" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash 0.5.1", ] [[package]] @@ -5444,14 +5489,14 @@ version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" dependencies = [ - "portable-atomic 1.5.1", + "portable-atomic 1.6.0", ] [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "postcard" @@ -5740,9 +5785,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c78e758510582acc40acb90458401172d41f1016f8c9dde89e49677afb7eec1" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand 0.8.5", @@ -5765,7 +5810,7 @@ dependencies = [ "libc", "socket2 0.5.5", "tracing", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -6103,7 +6148,7 @@ source = "git+https://github.com/paradigmxyz/reth.git?rev=aa6f2cb0610fb4fa0926b4 dependencies = [ "async-trait", "bytes", - "ethers-core 2.0.10 (git+https://github.com/gakonst/ethers-rs)", + "ethers-core 2.0.11", "futures", "metrics", "pin-project", @@ -6200,7 +6245,7 @@ dependencies = [ "crc", "crunchy", "derive_more", - "ethers-core 2.0.10 (git+https://github.com/gakonst/ethers-rs)", + "ethers-core 2.0.11", "fixed-hash", "hash-db", "hex", @@ -6322,7 +6367,7 @@ dependencies = [ "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -6379,9 +6424,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95294d6e3a6192f3aabf91c38f56505a625aa495533442744185a36d75a790c4" +checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" dependencies = [ "alloy-rlp 0.3.3", "ark-ff 0.3.0", @@ -6389,6 +6434,7 @@ dependencies = [ "bytes", "fastrlp", "num-bigint", + "num-traits", "parity-scale-codec", "primitive-types", "proptest", @@ -6469,20 +6515,6 @@ dependencies = [ "nom", ] -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys", -] - [[package]] name = "rustix" version = "0.38.21" @@ -6492,8 +6524,8 @@ dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys", + "linux-raw-sys", + "windows-sys 0.48.0", ] [[package]] @@ -6632,7 +6664,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -6967,10 +6999,10 @@ dependencies = [ "silius-bundler", "silius-contracts", "silius-grpc", + "silius-mempool", "silius-p2p", "silius-primitives", "silius-rpc", - "silius-uopool", "tokio", "tracing", "tracing-subscriber", @@ -7037,15 +7069,42 @@ dependencies = [ "serde_json", "silius-bundler", "silius-contracts", + "silius-mempool", "silius-p2p", "silius-primitives", - "silius-uopool", "tokio", "tonic", "tonic-build", "tracing", ] +[[package]] +name = "silius-mempool" +version = "0.3.0-alpha" +dependencies = [ + "alloy-chains", + "async-trait", + "bin-layout", + "educe", + "enumset", + "ethers 2.0.8", + "eyre", + "futures", + "futures-util", + "page_size 0.5.0", + "parking_lot 0.12.1", + "prost", + "reth-db", + "reth-libmdbx", + "serde", + "serde_json", + "silius-contracts", + "silius-primitives", + "tempdir", + "tokio", + "tracing", +] + [[package]] name = "silius-p2p" version = "0.3.0-alpha" @@ -7131,39 +7190,12 @@ dependencies = [ "futures", "parking_lot 0.12.1", "silius-contracts", + "silius-mempool", "silius-primitives", - "silius-uopool", "tempdir", "tokio", ] -[[package]] -name = "silius-uopool" -version = "0.3.0-alpha" -dependencies = [ - "alloy-chains", - "async-trait", - "bin-layout", - "educe", - "enumset", - "ethers 2.0.8", - "eyre", - "futures", - "futures-util", - "page_size 0.5.0", - "parking_lot 0.12.1", - "prost", - "reth-db", - "reth-libmdbx", - "serde", - "serde_json", - "silius-contracts", - "silius-primitives", - "tempdir", - "tokio", - "tracing", -] - [[package]] name = "simple_asn1" version = "0.6.2" @@ -7232,16 +7264,16 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" +checksum = "58021967fd0a5eeeb23b08df6cc244a4d4a5b4aec1d27c9e02fad1a58b4cd74e" dependencies = [ - "aes-gcm", + "aes-gcm 0.10.3", "blake2", "chacha20poly1305", "curve25519-dalek", "rand_core 0.6.4", - "ring 0.16.20", + "ring 0.17.5", "rustc_version 0.4.0", "sha2 0.10.8", "subtle", @@ -7264,7 +7296,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -7575,10 +7607,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", - "fastrand 2.0.1", + "fastrand", "redox_syscall 0.4.1", - "rustix 0.38.21", - "windows-sys", + "rustix", + "windows-sys 0.48.0", ] [[package]] @@ -7711,7 +7743,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -8228,6 +8260,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsigned-varint" version = "0.7.2" @@ -8326,12 +8368,6 @@ dependencies = [ "libc", ] -[[package]] -name = "waker-fn" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" - [[package]] name = "walkdir" version = "2.4.0" @@ -8467,7 +8503,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.21", + "rustix", ] [[package]] @@ -8514,7 +8550,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ "windows-core", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -8523,7 +8559,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -8532,7 +8568,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -8541,13 +8586,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 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", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -8556,42 +8616,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.17" @@ -8608,7 +8710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -8685,9 +8787,9 @@ dependencies = [ [[package]] name = "yamux" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0329ef377816896f014435162bb3711ea7a07729c23d0960e6f8048b21b8fe91" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" dependencies = [ "futures", "log", diff --git a/Cargo.toml b/Cargo.toml index 2b614bcf..765ac548 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,50 +4,75 @@ members = [ "crates/bundler", "crates/contracts", "crates/grpc", + "crates/mempool", "crates/p2p", "crates/primitives", "crates/rpc", - "crates/uopool", "examples/*", "tests", ] -default-members = ["bin/silius"] - -# Explicitly set the resolver to version 2, which is the default for packages with edition >= 2021 -# https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html resolver = "2" +default-members = ["bin/silius"] [workspace.package] -authors = ["Vid Kersic "] version = "0.3.0-alpha" +authors = ["Vid Kersic "] edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/silius-rs/silius" rust-version = "1.73.0" +keywords = [ + "silius", + "primitives", + "ethereum", + "account abstraction", + "erc-4337", +] +categories = ["data-structures", "cryptography::cryptocurrencies"] +description = "Silius - modular and efficient account abstraction (ERC-4337) bundler" +homepage = "https://silius.rs" + +[profile.debug-fast] +inherits = "release" +debug = true [workspace.dependencies] +# workspace crates +silius-bundler = { version = "0.3.0-alpha", path = "crates/bundler", default-features = false } +silius-contracts = { version = "0.3.0-alpha", path = "crates/contracts", default-features = false } +silius-grpc = { version = "0.3.0-alpha", path = "crates/grpc", default-features = false } +silius-mempool = { version = "0.3.0-alpha", path = "crates/mempool", default-features = false } +silius-p2p = { version = "0.3.0-alpha", path = "crates/p2p", default-features = false } +silius-primitives = { version = "0.3.0-alpha", path = "crates/primitives", default-features = false } +silius-rpc = { version = "0.3.0-alpha", path = "crates/rpc", default-features = false } +silius-tests = { version = "0.3.0-alpha", path = "tests", default-features = false } + +# eth alloy-chains = "0.1.2" -async-stream = "0.3.5" -async-trait = "0.1" discv5 = { version = "0.3.1", features = ["libp2p"] } ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "fa3017715a298728d9fb341933818a5d0d84c2dc", features = [ "ws", ] } +ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs.git", rev = "8640128ec83071094d24fb4511147d6b9dd029bb" } +ssz_rs_derive = { git = "https://github.com/ralexstokes/ssz-rs.git", rev = "8640128ec83071094d24fb4511147d6b9dd029bb" } + +# async +async-stream = "0.3.5" +async-trait = "0.1" +futures-util = "0.3.28" + +# tokio +tokio = { version = "1.18", features = ["full"] } + +# misc expanded-pathbuf = "0.1" eyre = "0.6.8" -futures-util = "0.3.28" lazy_static = "1.4.0" parking_lot = "0.12" serde_json = "1" -ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs.git", rev = "8640128ec83071094d24fb4511147d6b9dd029bb" } -ssz_rs_derive = { git = "https://github.com/ralexstokes/ssz-rs.git", rev = "8640128ec83071094d24fb4511147d6b9dd029bb" } -tokio = { version = "1.18", features = ["full"] } +thiserror = "1" tracing = "0.1" -[profile.debug-fast] -inherits = "release" -debug = true - [patch] [patch.crates-io] revm-primitives = { git = "https://github.com/bluealloy/revm", rev = "3d8ca6641d2e72448c23f4596f769c8fd1c784d1" } diff --git a/LICENSE-MIT b/LICENSE-MIT index db500a21..006eab71 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2022-2023 Reth Contributors +Copyright (c) 2022-2023 Silius Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index e5522299..3cba2b30 100644 --- a/Makefile +++ b/Makefile @@ -39,13 +39,13 @@ test: cargo test --workspace format: - cargo fmt --all - cargo sort --workspace + cargo +nightly fmt --all + cargo sort --workspace --grouped lint: - cargo fmt --all -- --check + cargo +nightly fmt --all -- --check cargo clippy --all -- -D warnings -A clippy::derive_partial_eq_without_eq -D clippy::unwrap_used -D clippy::uninlined_format_args - cargo sort --check --workspace + cargo sort --check --workspace --grouped cargo udeps --workspace run-geth: diff --git a/README.md b/README.md index aeb15b06..c1a0204b 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ cargo run --release -- rpc --http --ws ### Docker ```bash -docker run --net=host -v ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266:/data/silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -v ./db:/data/silius/db ghcr.io/silius-rs/silius:latest node --eth-client-address http://127.0.0.1:8545 --datadir data/silius --mnemonic-file data/silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789 --http --http.addr 0.0.0.0 --http.port 3000 --http.api eth,debug,web3 --ws --ws.addr 0.0.0.0 --ws.port 3001 --ws.api eth,debug,web3 --eth-client-proxy-address http://127.0.0.1:8545 +docker run --net=host -v ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266:/data/silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -v ./.local/db:/data/silius/db ghcr.io/silius-rs/silius:latest node --eth-client-address http://127.0.0.1:8545 --datadir data/silius --mnemonic-file data/silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789 --http --http.addr 0.0.0.0 --http.port 3000 --http.api eth,debug,web3 --ws --ws.addr 0.0.0.0 --ws.port 3001 --ws.api eth,debug,web3 --eth-client-proxy-address http://127.0.0.1:8545 ``` ## Supported networks diff --git a/bin/silius/Cargo.toml b/bin/silius/Cargo.toml index f0d4d4a9..ef21acec 100644 --- a/bin/silius/Cargo.toml +++ b/bin/silius/Cargo.toml @@ -6,28 +6,40 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler - Silius -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Silius - account abstraction (ERC-4337) bundler" +homepage = "https://github.com/silius-rs/silius/tree/main/bin/silius" [dependencies] +# workspace dependencies +silius-bundler = { workspace = true } +silius-contracts = { workspace = true } +silius-grpc = { workspace = true } +silius-mempool = { workspace = true } +silius-p2p = { workspace = true } +silius-primitives = { workspace = true } +silius-rpc = { workspace = true } + +# eth alloy-chains = { workspace = true } -clap = { version = "4", features = ["derive"] } -dirs = "4.0" discv5 = { workspace = true } ethers = { workspace = true } -expanded-pathbuf = { workspace = true } -eyre = { workspace = true } -log = "0.4.19" + +# cli +clap = { version = "4", features = ["derive"] } + +# async parking_lot = { workspace = true } pin-utils = "0.1" -silius-bundler = { path = "../../crates/bundler" } -silius-contracts = { path = "../../crates/contracts" } -silius-grpc = { path = "../../crates/grpc" } -silius-p2p = { path = "../../crates/p2p" } -silius-primitives = { path = "../../crates/primitives" } -silius-rpc = { path = "../../crates/rpc" } -silius-uopool = { path = "../../crates/uopool" } + +# tokio tokio = { workspace = true } + +# misc +dirs = "4.0" +expanded-pathbuf = { workspace = true } +eyre = { workspace = true } +log = "0.4.19" tracing = { workspace = true } tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/bin/silius/README.md b/bin/silius/README.md new file mode 100644 index 00000000..2c0e9b20 --- /dev/null +++ b/bin/silius/README.md @@ -0,0 +1,3 @@ +# silius + +TODO diff --git a/bin/silius/src/bundler.rs b/bin/silius/src/bundler.rs index e6bde51a..640a377f 100644 --- a/bin/silius/src/bundler.rs +++ b/bin/silius/src/bundler.rs @@ -12,15 +12,19 @@ use silius_grpc::{ bundler_client::BundlerClient, bundler_service_run, uo_pool_client::UoPoolClient, uopool_service_run, }; +use silius_mempool::{ + init_env, + validate::validator::{new_canonical, new_canonical_unsafe}, + CodeHashes, DatabaseTable, EntitiesReputation, Mempool, Reputation, UserOperations, + UserOperationsByEntity, UserOperationsBySender, WriteMap, +}; use silius_primitives::{ - bundler::SendBundleMode, - consts::{ + bundler::SendStrategy, + constants::{ entry_point, flashbots_relay_endpoints, p2p::{NODE_ENR_FILE_NAME, NODE_KEY_FILE_NAME}, - }, - consts::{ - p2p::DB_FOLDER_NAME, - reputation::{ + storage::DATABASE_FOLDER_NAME, + validation::reputation::{ BAN_SLACK, MIN_INCLUSION_RATE_DENOMINATOR, MIN_UNSTAKE_DELAY, THROTTLING_SLACK, }, }, @@ -35,12 +39,6 @@ use silius_rpc::{ web3_api::{Web3ApiServer, Web3ApiServerImpl}, JsonRpcServer, JsonRpcServerType, }; -use silius_uopool::{ - init_env, - validate::validator::{new_canonical, new_canonical_unsafe}, - CodeHashes, DatabaseTable, EntitiesReputation, Mempool, Reputation, UserOperations, - UserOperationsByEntity, UserOperationsBySender, WriteMap, -}; use std::{ collections::{HashMap, HashSet}, future::pending, @@ -75,23 +73,14 @@ where eth_client.clone(), common_args.chain, common_args.entry_points, - format!( - "http://{:?}:{:?}", - uopool_args.uopool_addr, uopool_args.uopool_port - ), + format!("http://{:?}:{:?}", uopool_args.uopool_addr, uopool_args.uopool_port), ) .await?; launch_rpc( rpc_args, - format!( - "http://{:?}:{:?}", - uopool_args.uopool_addr, uopool_args.uopool_port - ), - format!( - "http://{:?}:{:?}", - bundler_args.bundler_addr, bundler_args.bundler_port - ), + format!("http://{:?}:{:?}", uopool_args.uopool_addr, uopool_args.uopool_port), + format!("http://{:?}:{:?}", bundler_args.bundler_addr, bundler_args.bundler_port), ) .await?; @@ -120,7 +109,7 @@ where let chain_conn = Chain::from(chain_id.as_u64()); let wallet: Wallet; - if args.send_bundle_mode == SendBundleMode::Flashbots { + if args.send_bundle_mode == SendStrategy::Flashbots { wallet = Wallet::from_file(args.mnemonic_file.into(), &chain_id, true) .map_err(|error| eyre::format_err!("Could not load mnemonic file: {}", error))?; info!("Wallet Signer {:?}", wallet.signer); @@ -147,16 +136,11 @@ where uopool_grpc_client, args.send_bundle_mode, match args.send_bundle_mode { - SendBundleMode::EthClient => None, - SendBundleMode::Flashbots => { - Some(vec![flashbots_relay_endpoints::FLASHBOTS.to_string()]) - } + SendStrategy::EthClient => None, + SendStrategy::Flashbots => Some(vec![flashbots_relay_endpoints::FLASHBOTS.to_string()]), }, ); - info!( - "Started bundler gRPC service at {:?}:{:?}", - args.bundler_addr, args.bundler_port - ); + info!("Started bundler gRPC service at {:?}:{:?}", args.bundler_addr, args.bundler_port); Ok(()) } @@ -205,18 +189,10 @@ where args.min_priority_fee_per_gas, ); let mempool = Mempool::new( - Arc::new(RwLock::new( - HashMap::::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), + Arc::new(RwLock::new(HashMap::::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), ); let mut reputation = Reputation::new( MIN_INCLUSION_RATE_DENOMINATOR, @@ -248,10 +224,7 @@ where args.p2p_opts.bootnodes, ) .await?; - info!( - "Started uopool gRPC service at {:?}:{:?}", - args.uopool_addr, args.uopool_port - ); + info!("Started uopool gRPC service at {:?}:{:?}", args.uopool_addr, args.uopool_port); } (silius_primitives::UoPoolMode::Standard, StorageType::Database) => { let validator = new_canonical( @@ -261,10 +234,9 @@ where args.min_priority_fee_per_gas, ); let env = Arc::new( - init_env::(datadir.join(DB_FOLDER_NAME)).expect("Init mdbx failed"), + init_env::(datadir.join(DATABASE_FOLDER_NAME)).expect("Init mdbx failed"), ); - env.create_tables() - .expect("Create mdbx database tables failed"); + env.create_tables().expect("Create mdbx database tables failed"); let mempool = Mempool::new( DatabaseTable::::new(env.clone()), DatabaseTable::::new(env.clone()), @@ -301,10 +273,7 @@ where args.p2p_opts.bootnodes, ) .await?; - info!( - "Started uopool gRPC service at {:?}:{:?}", - args.uopool_addr, args.uopool_port - ); + info!("Started uopool gRPC service at {:?}:{:?}", args.uopool_addr, args.uopool_port); } (silius_primitives::UoPoolMode::Unsafe, StorageType::Memory) => { let validator = new_canonical_unsafe( @@ -314,18 +283,10 @@ where args.min_priority_fee_per_gas, ); let mempool = Mempool::new( - Arc::new(RwLock::new( - HashMap::::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), + Arc::new(RwLock::new(HashMap::::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), ); let mut reputation = Reputation::new( MIN_INCLUSION_RATE_DENOMINATOR, @@ -357,10 +318,7 @@ where args.p2p_opts.bootnodes, ) .await?; - info!( - "Started uopool gRPC service at {:?}:{:?}", - args.uopool_addr, args.uopool_port - ); + info!("Started uopool gRPC service at {:?}:{:?}", args.uopool_addr, args.uopool_port); } (silius_primitives::UoPoolMode::Unsafe, StorageType::Database) => { let validator = new_canonical_unsafe( @@ -370,10 +328,9 @@ where args.min_priority_fee_per_gas, ); let env = Arc::new( - init_env::(datadir.join(DB_FOLDER_NAME)).expect("Init mdbx failed"), + init_env::(datadir.join(DATABASE_FOLDER_NAME)).expect("Init mdbx failed"), ); - env.create_tables() - .expect("Create mdbx database tables failed"); + env.create_tables().expect("Create mdbx database tables failed"); let mempool = Mempool::new( DatabaseTable::::new(env.clone()), DatabaseTable::::new(env.clone()), @@ -410,10 +367,7 @@ where args.p2p_opts.bootnodes, ) .await?; - info!( - "Started uopool gRPC service at {:?}:{:?}", - args.uopool_addr, args.uopool_port - ); + info!("Started uopool gRPC service at {:?}:{:?}", args.uopool_addr, args.uopool_port); } }; @@ -463,19 +417,13 @@ pub async fn launch_rpc( if args.is_api_method_enabled("eth") { if http_api.contains("eth") { server.add_methods( - EthApiServerImpl { - uopool_grpc_client: uopool_grpc_client.clone(), - } - .into_rpc(), + EthApiServerImpl { uopool_grpc_client: uopool_grpc_client.clone() }.into_rpc(), JsonRpcServerType::Http, )?; } if ws_api.contains("eth") { server.add_methods( - EthApiServerImpl { - uopool_grpc_client: uopool_grpc_client.clone(), - } - .into_rpc(), + EthApiServerImpl { uopool_grpc_client: uopool_grpc_client.clone() }.into_rpc(), JsonRpcServerType::Ws, )?; } @@ -499,11 +447,7 @@ pub async fn launch_rpc( if ws_api.contains("debug") { server.add_methods( - DebugApiServerImpl { - uopool_grpc_client, - bundler_grpc_client, - } - .into_rpc(), + DebugApiServerImpl { uopool_grpc_client, bundler_grpc_client }.into_rpc(), JsonRpcServerType::Ws, )?; } @@ -523,10 +467,7 @@ pub async fn launch_rpc( } pub fn create_wallet(args: CreateWalletArgs) -> eyre::Result<()> { - info!( - "Creating bundler wallet... Storing to: {:?}", - args.output_path - ); + info!("Creating bundler wallet... Storing to: {:?}", args.output_path); let path = unwrap_path_or_home(args.output_path)?; diff --git a/bin/silius/src/cli/args.rs b/bin/silius/src/cli/args.rs index cfeabd52..a50f85d5 100644 --- a/bin/silius/src/cli/args.rs +++ b/bin/silius/src/cli/args.rs @@ -7,12 +7,11 @@ use ethers::types::{Address, U256}; use expanded_pathbuf::ExpandedPathBuf; use silius_p2p::config::{Config, ListenAddr}; use silius_primitives::{ - bundler::{SendBundleMode, DEFAULT_BUNDLE_INTERVAL}, - consts::{ - networking::{ - DEFAULT_BUNDLER_GRPC_PORT, DEFAULT_HTTP_RPC_PORT, DEFAULT_UOPOOL_GRPC_PORT, - DEFAULT_WS_RPC_PORT, - }, + bundler::SendStrategy, + constants::{ + bundler::BUNDLE_INTERVAL, + grpc::{BUNDLER_PORT, MEMPOOL_PORT}, + rpc::{HTTP_PORT, WS_PORT}, supported_chains::SUPPORTED_NAMED_CHAINS, }, UoPoolMode, @@ -36,7 +35,7 @@ pub struct BundlerArgs { pub bundler_addr: IpAddr, /// Bundler gRPC port to listen on. - #[clap(long = "bundler.port", default_value_t = DEFAULT_BUNDLER_GRPC_PORT)] + #[clap(long = "bundler.port", default_value_t = BUNDLER_PORT)] pub bundler_port: u16, /// Path to the mnemonic file. @@ -56,14 +55,14 @@ pub struct BundlerArgs { /// The bundle interval in seconds. /// /// By default the interval time is set to 10 - #[clap(long, default_value_t = DEFAULT_BUNDLE_INTERVAL)] + #[clap(long, default_value_t = BUNDLE_INTERVAL)] pub bundle_interval: u64, /// Sets the send bundle mode. /// /// By default, this option is set to `eth-client`. #[clap(long, default_value = "eth-client", value_parser=parse_send_bundle_mode)] - pub send_bundle_mode: SendBundleMode, + pub send_bundle_mode: SendStrategy, } /// UoPool CLI args @@ -74,7 +73,7 @@ pub struct UoPoolArgs { pub uopool_addr: IpAddr, /// UoPool gRPC port to listen on. - #[clap(long = "uopool.port", default_value_t = DEFAULT_UOPOOL_GRPC_PORT)] + #[clap(long = "uopool.port", default_value_t = MEMPOOL_PORT)] pub uopool_port: u16, /// Data directory (primarily for database). @@ -147,7 +146,7 @@ pub struct RpcArgs { /// Sets the HTTP RPC port to listen on. /// /// By default, this option is set to `3000` - #[clap(long = "http.port", default_value_t = DEFAULT_HTTP_RPC_PORT)] + #[clap(long = "http.port", default_value_t = HTTP_PORT)] pub http_port: u16, /// Configures the HTTP RPC API modules. @@ -177,7 +176,7 @@ pub struct RpcArgs { /// Sets the WS RPC port to listen on. /// /// By default, this option is set to `3001` - #[clap(long = "ws.port", default_value_t = DEFAULT_WS_RPC_PORT)] + #[clap(long = "ws.port", default_value_t = WS_PORT)] pub ws_port: u16, /// Configures the WS RPC API modules. @@ -321,7 +320,7 @@ mod tests { .unwrap(), min_balance: U256::from(100000000000000000_u64), bundle_interval: 10, - send_bundle_mode: SendBundleMode::EthClient, + send_bundle_mode: SendStrategy::EthClient, bundler_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), bundler_port: 3002, }, @@ -357,20 +356,12 @@ mod tests { http: true, http_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), http_port: 3000, - http_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + http_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], http_corsdomain: vec![String::from("127.0.0.1:4321")], ws: true, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), ws_port: 3001, - ws_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + ws_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], ws_origins: vec![String::from("127.0.0.1:4321")], eth_client_proxy_address: None, }, @@ -397,11 +388,7 @@ mod tests { http: true, http_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), http_port: 3000, - http_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + http_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], http_corsdomain: vec![String::from("127.0.0.1:4321")], ws: false, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), @@ -438,11 +425,7 @@ mod tests { ws: true, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), ws_port: 3001, - ws_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + ws_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], ws_origins: vec![String::from("127.0.0.1:4321")], eth_client_proxy_address: None, }, @@ -468,11 +451,7 @@ mod tests { http: false, http_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), http_port: 3000, - http_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + http_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], http_corsdomain: vec![String::from("127.0.0.1:4321")], ws: false, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), @@ -492,11 +471,7 @@ mod tests { http: true, http_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), http_port: 3000, - http_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + http_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], http_corsdomain: vec![String::from("127.0.0.1:4321")], ws: false, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), @@ -522,11 +497,7 @@ mod tests { ws: true, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), ws_port: 3001, - ws_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + ws_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], ws_origins: vec![String::from("127.0.0.1:4321")], eth_client_proxy_address: None, } @@ -542,20 +513,12 @@ mod tests { http: true, http_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), http_port: 3000, - http_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + http_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], http_corsdomain: vec![String::from("127.0.0.1:4321")], ws: true, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), ws_port: 3001, - ws_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + ws_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], ws_origins: vec![String::from("127.0.0.1:4321")], eth_client_proxy_address: None, } @@ -571,11 +534,7 @@ mod tests { http: false, http_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), http_port: 3000, - http_api: vec![ - String::from("eth"), - String::from("debug"), - String::from("web3") - ], + http_api: vec![String::from("eth"), String::from("debug"), String::from("web3")], http_corsdomain: vec![String::from("127.0.0.1:4321")], ws: false, ws_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), diff --git a/bin/silius/src/cli/commands.rs b/bin/silius/src/cli/commands.rs index 72051b2c..e0aaa6f2 100644 --- a/bin/silius/src/cli/commands.rs +++ b/bin/silius/src/cli/commands.rs @@ -170,12 +170,8 @@ pub struct RpcCommand { impl RpcCommand { /// Execute the command pub async fn execute(self) -> eyre::Result<()> { - launch_rpc( - self.rpc, - self.uopool_grpc_listen_address, - self.bundler_grpc_listen_address, - ) - .await?; + launch_rpc(self.rpc, self.uopool_grpc_listen_address, self.bundler_grpc_listen_address) + .await?; pending().await } } diff --git a/bin/silius/src/cli/mod.rs b/bin/silius/src/cli/mod.rs index 09a0db97..b281c28d 100644 --- a/bin/silius/src/cli/mod.rs +++ b/bin/silius/src/cli/mod.rs @@ -35,7 +35,8 @@ impl Cli { /// Commands to be executed #[derive(Debug, Subcommand)] pub enum Commands { - /// Start the bundler with all components (bundling component, user operation mempool, RPC server) + /// Start the bundler with all components (bundling component, user operation mempool, RPC + /// server) #[command(name = "node")] Node(Box), diff --git a/bin/silius/src/utils.rs b/bin/silius/src/utils.rs index 64b1a0c6..59cac4a4 100644 --- a/bin/silius/src/utils.rs +++ b/bin/silius/src/utils.rs @@ -3,7 +3,7 @@ use discv5::Enr; use ethers::types::{Address, U256}; use expanded_pathbuf::ExpandedPathBuf; use pin_utils::pin_mut; -use silius_primitives::{bundler::SendBundleMode, UoPoolMode}; +use silius_primitives::{bundler::SendStrategy, UoPoolMode}; use std::{future::Future, str::FromStr}; use tracing::info; @@ -30,8 +30,8 @@ pub fn parse_u256(s: &str) -> Result { } /// Parses SendBundleMode from string -pub fn parse_send_bundle_mode(s: &str) -> Result { - SendBundleMode::from_str(s).map_err(|_| format!("String {s} is not a valid SendBundleMode")) +pub fn parse_send_bundle_mode(s: &str) -> Result { + SendStrategy::from_str(s).map_err(|_| format!("String {s} is not a valid SendBundleMode")) } /// Parses UoPoolMode from string diff --git a/crates/bundler/Cargo.toml b/crates/bundler/Cargo.toml index 245ad350..c7b04d6a 100644 --- a/crates/bundler/Cargo.toml +++ b/crates/bundler/Cargo.toml @@ -6,29 +6,44 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler bundling implementation -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-4337) bundling implementation" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/bundler" [dependencies] +# workspace dependencies +silius-contracts = { workspace = true } +silius-primitives = { workspace = true } + +# eth alloy-chains = { workspace = true } -async-trait = "0.1" -bytes = "1.4.0" ethers = { workspace = true } ethers-flashbots = { git = "https://github.com/qi-protocol/ethers-flashbots.git", rev = "1c6504cd2d1f4d67e4af2dd9a5ee676a284452f9" } + +# async +async-trait = "0.1" + +# tokio +tokio = { workspace = true } + +# misc +bytes = "1.4.0" eyre = { workspace = true } serde = { version = "1.0", features = ["derive"] } serde_json = "1" -silius-contracts = { path = "../contracts" } -silius-primitives = { path = "../primitives" } -tokio = { workspace = true } tracing = { workspace = true } url = "2.4.0" [dev-dependencies] +# eth alloy-primitives = "0.2.0" alloy-sol-types = "0.2.0" -dotenv = "0.15.0" ethers-flashbots-test = { git = "https://github.com/da-bao-jian/ethers-flashbots.git", rev = "1eda9b7bb84e82f43f35b98c34d9066f9596b41d" } + +# rpc jsonrpsee = { version = "0.20.0", features = ["server", "macros", "client"] } + +# misc +dotenv = "0.15.0" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/crates/bundler/README.md b/crates/bundler/README.md new file mode 100644 index 00000000..3958577f --- /dev/null +++ b/crates/bundler/README.md @@ -0,0 +1,3 @@ +# silius-bundler + +TODO \ No newline at end of file diff --git a/crates/bundler/src/bundler.rs b/crates/bundler/src/bundler.rs index 12f8014a..0d7ef3fc 100644 --- a/crates/bundler/src/bundler.rs +++ b/crates/bundler/src/bundler.rs @@ -12,8 +12,8 @@ use ethers_flashbots::{ }; use silius_contracts::entry_point::EntryPointAPI; use silius_primitives::{ - bundler::SendBundleMode, - consts::{flashbots_relay_endpoints, supported_chains}, + bundler::SendStrategy, + constants::{flashbots_relay_endpoints, supported_chains}, UserOperation, Wallet, }; use std::{sync::Arc, time::Duration}; @@ -41,8 +41,9 @@ where pub entry_point: Address, /// [Chain](Chain) instance representing the blockchain network to be used pub chain: Chain, - /// Send bundle mode determines whether to send the bundle to a regular Eth execution client or to Flashbots - pub send_bundle_mode: SendBundleMode, + /// Send bundle mode determines whether to send the bundle to a regular Eth execution client or + /// to Flashbots + pub send_bundle_mode: SendStrategy, /// Block Builder relay endpoints pub relay_endpoints: Option>, /// Ethereum signer middleware @@ -58,7 +59,8 @@ where M: Middleware + 'static, { /// Create a new `Bundler` instance - /// if `send_bundle_mode` is `SendBundleMode::Flashbots` and `relay_endpoints` is `None`, the default Flashbots relay endpoint will be used + /// if `send_bundle_mode` is `SendBundleMode::Flashbots` and `relay_endpoints` is `None`, the + /// default Flashbots relay endpoint will be used /// /// # Returns /// * `Self` - A new `Bundler` instance @@ -69,24 +71,22 @@ where beneficiary: Address, entry_point: Address, chain: Chain, - send_bundle_mode: SendBundleMode, + send_bundle_mode: SendStrategy, relay_endpoints: Option>, min_balance: U256, ) -> eyre::Result { - if !(chain.id() == supported_chains::MAINNET - || chain.id() == supported_chains::GOERLI - || chain.id() == supported_chains::SEPOLIA) - && send_bundle_mode == SendBundleMode::Flashbots + if !(chain.id() == supported_chains::MAINNET || + chain.id() == supported_chains::GOERLI || + chain.id() == supported_chains::SEPOLIA) && + send_bundle_mode == SendStrategy::Flashbots { panic!("Flashbots is only supported on Mainnet, Goerli and Sepolia"); }; match send_bundle_mode { - SendBundleMode::EthClient => { - let client = Arc::new(SignerMiddleware::new( - eth_client.clone(), - wallet.signer.clone(), - )); + SendStrategy::EthClient => { + let client = + Arc::new(SignerMiddleware::new(eth_client.clone(), wallet.signer.clone())); Ok(Self { wallet, @@ -100,7 +100,7 @@ where min_balance, }) } - SendBundleMode::Flashbots => match relay_endpoints { + SendStrategy::Flashbots => match relay_endpoints { None => { let relay_endpoints = vec![flashbots_relay_endpoints::FLASHBOTS.to_string()]; let flashbots_client = generate_flashbots_middleware( @@ -144,7 +144,8 @@ where } } - /// Send a bundle of [UserOperations](UserOperation) to the Ethereum execution client or Flashbots' relay, depending on the [SendBundleMode](SendBundleMode) + /// Send a bundle of [UserOperations](UserOperation) to the Ethereum execution client or + /// Flashbots' relay, depending on the [SendBundleMode](SendBundleMode) /// /// # Arguments /// * `uos` - An array of [UserOperations](UserOperation) @@ -161,12 +162,13 @@ where trace!("Bundle content: {uos:?}"); match self.send_bundle_mode { - SendBundleMode::EthClient => self.send_next_bundle_eth(uos).await, - SendBundleMode::Flashbots => self.send_next_bundle_flashbots(uos).await, + SendStrategy::EthClient => self.send_next_bundle_eth(uos).await, + SendStrategy::Flashbots => self.send_next_bundle_flashbots(uos).await, } } - /// Helper function to generate a [TypedTransaction](TypedTransaction) from an array of user operations. + /// Helper function to generate a [TypedTransaction](TypedTransaction) from an array of user + /// operations. /// /// # Arguments /// * `client` - A provider that implements [Middleware](Middleware) trait @@ -184,26 +186,17 @@ where { let ep = EntryPointAPI::new(self.entry_point, client.clone()); - let nonce = client - .clone() - .get_transaction_count(self.wallet.signer.address(), None) - .await?; - let balance = client - .clone() - .get_balance(self.wallet.signer.address(), None) - .await?; + let nonce = + client.clone().get_transaction_count(self.wallet.signer.address(), None).await?; + let balance = client.clone().get_balance(self.wallet.signer.address(), None).await?; let beneficiary = if balance < self.min_balance { self.wallet.signer.address() } else { self.beneficiary }; - let mut tx: TypedTransaction = ep - .handle_ops( - uos.clone().into_iter().map(Into::into).collect(), - beneficiary, - ) - .tx; + let mut tx: TypedTransaction = + ep.handle_ops(uos.clone().into_iter().map(Into::into).collect(), beneficiary).tx; match self.chain.id() { // Mumbai @@ -212,11 +205,7 @@ where } // All other surpported networks, including Mainnet, Goerli _ => { - let accesslist = client - .clone() - .create_access_list(&tx, None) - .await? - .access_list; + let accesslist = client.clone().create_access_list(&tx, None).await?.access_list; tx.set_access_list(accesslist.clone()); let estimated_gas = client.clone().estimate_gas(&tx, None).await?; @@ -258,10 +247,7 @@ where trace!("Sending transaction to the execution client: {tx:?}"); - let tx = client - .send_transaction(tx, None) - .await? - .interval(Duration::from_millis(75)); + let tx = client.send_transaction(tx, None).await?.interval(Duration::from_millis(75)); let tx_hash = tx.tx_hash(); let tx_receipt = tx.await?; @@ -353,16 +339,10 @@ async fn simulate_flashbots_bundle( for tx in &simulated_bundle.transactions { trace!("Simulate bundle: {:?}", tx); if let Some(err) = &tx.error { - return Err(eyre::eyre!( - "Transaction failed simulation with error: {:?}", - err - )); + return Err(eyre::eyre!("Transaction failed simulation with error: {:?}", err)); } if let Some(revert) = &tx.revert { - return Err(eyre::eyre!( - "Transaction failed simulation with revert: {:?}", - revert - )); + return Err(eyre::eyre!("Transaction failed simulation with revert: {:?}", revert)); } } @@ -374,7 +354,8 @@ async fn simulate_flashbots_bundle( /// # Arguments /// * `client` - An [Flashbots SignerMiddleware](FlashbotsSignerMiddleware) /// * `tx` - A [EIP-1559 TypedTransaction](TypedTransaction) -/// * `revertible` - If true the bundle is revertible, otherwise any transactions in the bundle revert will revert the whole bundle +/// * `revertible` - If true the bundle is revertible, otherwise any transactions in the bundle +/// revert will revert the whole bundle /// /// # Returns /// * `BundleRequest` - A [BundleRequest](BundleRequest) @@ -434,20 +415,14 @@ pub(crate) fn generate_flashbots_middleware( None => return Err(eyre::eyre!("No Flashbots signer provided")), }; - let mut flashbots_middleware = FlashbotsMiddleware::new( - eth_client, - Url::parse(relay_endpoint)?, - bundle_signer.clone(), - ); + let mut flashbots_middleware = + FlashbotsMiddleware::new(eth_client, Url::parse(relay_endpoint)?, bundle_signer.clone()); flashbots_middleware.set_simulation_relay( Url::parse(relay_endpoint).expect("Failed to parse simulation relay URL"), bundle_signer.clone(), ); - let client = Arc::new(SignerMiddleware::new( - flashbots_middleware, - wallet.signer.clone(), - )); + let client = Arc::new(SignerMiddleware::new(flashbots_middleware, wallet.signer.clone())); Ok(client) } @@ -476,7 +451,7 @@ mod test { utils::{parse_units, Anvil, AnvilInstance}, }; use jsonrpsee::server::{ServerBuilder, ServerHandle}; - use silius_primitives::{bundler::SendBundleMode, consts::flashbots_relay_endpoints, Wallet}; + use silius_primitives::{bundler::SendStrategy, constants::flashbots_relay_endpoints, Wallet}; use std::sync::Arc; sol! { @@ -549,25 +524,19 @@ mod test { wallet.signer.address(), ep_address, Chain::from(1), - SendBundleMode::Flashbots, + SendStrategy::Flashbots, Some(vec![flashbots_relay_endpoints::FLASHBOTS.to_string()]), U256::from(100000000000000000u64), ) .expect("Failed to create bundler"); - Ok(TestContext { - bundler, - entry_point: ep_address, - anvil, - }) + Ok(TestContext { bundler, entry_point: ep_address, anvil }) } async fn start_mock_server() -> eyre::Result<(ServerHandle, MockFlashbotsBlockBuilderRelay)> { // Start a mock server connecting to the Anvil, exposing the port at 3001 let mock_relay = MockFlashbotsBlockBuilderRelay::new(8545u64).await.unwrap(); - let server = ServerBuilder::new() - .build("127.0.0.1:3001".to_string()) - .await?; + let server = ServerBuilder::new().build("127.0.0.1:3001".to_string()).await?; let handle = server.start(mock_relay.clone().into_rpc()); Ok((handle, mock_relay)) @@ -592,7 +561,7 @@ mod test { wallet.signer.address(), ep_address, Chain::from(5), - SendBundleMode::Flashbots, + SendStrategy::Flashbots, Some(vec![flashbots_relay_endpoints::FLASHBOTS_GOERLI.to_string()]), U256::from(100000000000000000u64), ) @@ -616,9 +585,7 @@ mod test { let approve_call_data = approve.encode(); let address = bundler.wallet.signer.address(); - let nonce = flashbots_client - .get_transaction_count(address.clone(), None) - .await?; + let nonce = flashbots_client.get_transaction_count(address.clone(), None).await?; let (max_fee_per_gas, max_priority_fee) = eth_client.estimate_eip1559_fees(None).await?; @@ -663,9 +630,7 @@ mod test { let depositor = mock_relay.mock_eth_client.clone(); let address = bundler.wallet.signer.address(); - let eth_client = Arc::new(Provider::::try_from( - "http://127.0.0.1:8545".to_string(), - )?); + let eth_client = Arc::new(Provider::::try_from("http://127.0.0.1:8545".to_string())?); // Create a Flashbots signer middleware let flashbots_client = generate_flashbots_middleware( @@ -681,18 +646,10 @@ mod test { // Deposit 500 ETH to get WETH and transfer to the bundler let value = U256::from(parse_units("500.0", "ether").unwrap()); - let _ = depositor_weth_instance - .deposit() - .value(value) - .send() - .await? - .await?; - - let _ = depositor_weth_instance - .transfer(address.clone(), value.clone()) - .send() - .await? - .await?; + let _ = depositor_weth_instance.deposit().value(value).send().await?.await?; + + let _ = + depositor_weth_instance.transfer(address.clone(), value.clone()).send().await?.await?; let balance_before = flashbots_client.clone().get_balance(address, None).await?; @@ -727,10 +684,7 @@ mod test { }; let swap_call_data = swap_eth.encode(); - let nonce = flashbots_client - .clone() - .get_transaction_count(address, None) - .await?; + let nonce = flashbots_client.clone().get_transaction_count(address, None).await?; // Craft a bundle with approve() and swapExactETHForTokens() let approve_tx_req = TypedTransaction::Eip1559(Eip1559TransactionRequest { diff --git a/crates/bundler/src/mock_relay.rs b/crates/bundler/src/mock_relay.rs index 2a4f0b66..88a1b5d7 100644 --- a/crates/bundler/src/mock_relay.rs +++ b/crates/bundler/src/mock_relay.rs @@ -8,8 +8,7 @@ use ethers::{ use ethers_flashbots_test::{relay::SendBundleResponse, SimulatedBundle, SimulatedTransaction}; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use serde::{Deserialize, Serialize}; -use std::sync::Arc; -use std::time::Duration; +use std::{sync::Arc, time::Duration}; pub const INIT_BLOCK: u64 = 17832062; @@ -38,9 +37,7 @@ impl MockFlashbotsBlockBuilderRelay { .parse::()?; let client = Arc::new(SignerMiddleware::new(mock_eth_client.clone(), wallet)); - Ok(Self { - mock_eth_client: client, - }) + Ok(Self { mock_eth_client: client }) } } @@ -52,7 +49,8 @@ impl MockFlashbotsRelayServer for MockFlashbotsBlockBuilderRelay { tokio::spawn(async move { tokio::time::sleep(Duration::from_secs(12)).await; - // let _ = MockFlashbotsBlockBuilderRelay::create_pending_bundle(&provider, &bundle_req); + // let _ = MockFlashbotsBlockBuilderRelay::create_pending_bundle(&provider, + // &bundle_req); }); Ok(SendBundleResponse::default()) diff --git a/crates/contracts/Cargo.toml b/crates/contracts/Cargo.toml index 21751253..bde19650 100644 --- a/crates/contracts/Cargo.toml +++ b/crates/contracts/Cargo.toml @@ -6,25 +6,34 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler smart contract interfaces -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-4337) smart contract interfaces" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/contracts" [dependencies] +# workspace dependencies +silius-primitives = { workspace = true } +# eth ethers = { workspace = true } + +# misc eyre = { workspace = true } lazy_static = { workspace = true } regex = "1.9.6" serde = "1" serde_json = "1" -silius-primitives = { path = "../primitives" } -thiserror = "1" +thiserror = { workspace = true } [dev-dependencies] +# tokio tokio = { workspace = true } [build-dependencies] +# eth ethers = { workspace = true, features = ["solc-full"] } ethers-solc = "2.0.8" + +# misc eyre = { workspace = true } diff --git a/crates/contracts/README.md b/crates/contracts/README.md new file mode 100644 index 00000000..4124540a --- /dev/null +++ b/crates/contracts/README.md @@ -0,0 +1,3 @@ +# silius-contracts + +TODO \ No newline at end of file diff --git a/crates/contracts/build.rs b/crates/contracts/build.rs index edd9da86..1c8f266a 100644 --- a/crates/contracts/build.rs +++ b/crates/contracts/build.rs @@ -33,20 +33,12 @@ fn compile_aa_smart_contracts() -> eyre::Result<()> { let build_info = root.join("contracts").join("build-info"); // compile interfaces - compile( - &root, - &root.join("contracts").join("interfaces"), - &build_info, - &target, - )?; + compile(&root, &root.join("contracts").join("interfaces"), &build_info, &target)?; // compile sender creator smart contract compile( &root, - &root - .join("contracts") - .join("core") - .join("SenderCreator.sol"), + &root.join("contracts").join("core").join("SenderCreator.sol"), &build_info, &target, )?; diff --git a/crates/contracts/src/entry_point.rs b/crates/contracts/src/entry_point.rs index 69f3b33e..e408ce45 100644 --- a/crates/contracts/src/entry_point.rs +++ b/crates/contracts/src/entry_point.rs @@ -1,25 +1,29 @@ -use super::gen::entry_point_api::{ - EntryPointAPIErrors, FailedOp, SenderAddressResult, UserOperation, ValidationResult, - ValidationResultWithAggregation, -}; -use super::gen::stake_manager_api::DepositInfo; pub use super::gen::{ EntryPointAPI, EntryPointAPIEvents, StakeManagerAPI, UserOperationEventFilter, ValidatePaymasterUserOpReturn, SELECTORS_INDICES, SELECTORS_NAMES, }; -use super::tracer::JS_TRACER; +use super::{ + gen::{ + entry_point_api::{ + EntryPointAPIErrors, FailedOp, SenderAddressResult, UserOperation, ValidationResult, + ValidationResultWithAggregation, + }, + stake_manager_api::DepositInfo, + }, + tracer::JS_TRACER, +}; use crate::gen::ExecutionResult; -use ethers::abi::AbiDecode; -use ethers::prelude::{ContractError, Event}; -use ethers::providers::{JsonRpcError, Middleware, MiddlewareError, ProviderError}; -use ethers::types::{ - Address, Bytes, GethDebugTracerType, GethDebugTracingCallOptions, GethDebugTracingOptions, - GethTrace, TransactionRequest, U256, +use ethers::{ + abi::AbiDecode, + prelude::{ContractError, Event}, + providers::{JsonRpcError, Middleware, MiddlewareError, ProviderError}, + types::{ + Address, Bytes, GethDebugTracerType, GethDebugTracingCallOptions, GethDebugTracingOptions, + GethTrace, TransactionRequest, U256, + }, }; use regex::Regex; -use std::fmt::Display; -use std::str::FromStr; -use std::sync::Arc; +use std::{fmt::Display, str::FromStr, sync::Arc}; use thiserror::Error; #[derive(Clone, Debug, PartialEq, Eq)] @@ -40,12 +44,7 @@ impl EntryPoint { pub fn new(eth_client: Arc, address: Address) -> Self { let entry_point_api = EntryPointAPI::new(address, eth_client.clone()); let stake_manager_api = StakeManagerAPI::new(address, eth_client.clone()); - Self { - eth_client, - address, - entry_point_api, - stake_manager_api, - } + Self { eth_client, address, entry_point_api, stake_manager_api } } pub fn entry_point_api(&self) -> &EntryPointAPI { @@ -68,18 +67,16 @@ impl EntryPoint { err_msg: ContractError, ) -> Result { match err_msg { - ContractError::DecodingError(e) => Err(EntryPointErr::DecodeErr(format!( - "Decoding error on msg: {e:?}" - ))), - ContractError::AbiError(e) => Err(EntryPointErr::UnknownErr(format!( - "Contract call with abi error: {e:?} ", - ))), + ContractError::DecodingError(e) => { + Err(EntryPointErr::DecodeErr(format!("Decoding error on msg: {e:?}"))) + } + ContractError::AbiError(e) => { + Err(EntryPointErr::UnknownErr(format!("Contract call with abi error: {e:?} ",))) + } ContractError::MiddlewareError { e } => EntryPointErr::from_middleware_err::(e), ContractError::ProviderError { e } => EntryPointErr::from_provider_err(&e), ContractError::Revert(data) => decode_revert_error(data), - _ => Err(EntryPointErr::UnknownErr(format!( - "Unkown error: {err_msg:?}", - ))), + _ => Err(EntryPointErr::UnknownErr(format!("Unkown error: {err_msg:?}",))), } } @@ -98,9 +95,9 @@ impl EntryPoint { EntryPointAPIErrors::ValidationResult(res) => { Ok(SimulateValidationResult::ValidationResult(res)) } - EntryPointAPIErrors::ValidationResultWithAggregation(res) => Ok( - SimulateValidationResult::ValidationResultWithAggregation(res), - ), + EntryPointAPIErrors::ValidationResultWithAggregation(res) => { + Ok(SimulateValidationResult::ValidationResultWithAggregation(res)) + } _ => Err(EntryPointErr::UnknownErr(format!( "Simulate validation with invalid error: {op:?}" ))), @@ -164,9 +161,7 @@ impl EntryPoint { match res { Ok(deposit_info) => Ok(deposit_info), - _ => Err(EntryPointErr::UnknownErr( - "Error calling get deposit info".to_string(), - )), + _ => Err(EntryPointErr::UnknownErr("Error calling get deposit info".to_string())), } } @@ -175,9 +170,7 @@ impl EntryPoint { match res { Ok(balance) => Ok(balance), - _ => Err(EntryPointErr::UnknownErr( - "Error calling balance of".to_string(), - )), + _ => Err(EntryPointErr::UnknownErr("Error calling balance of".to_string())), } } @@ -192,11 +185,7 @@ impl EntryPoint { &self, init_code: Bytes, ) -> Result { - let res = self - .entry_point_api - .get_sender_address(init_code) - .call() - .await; + let res = self.entry_point_api.get_sender_address(init_code).call().await; match res { Ok(_) => Err(EntryPointErr::UnknownErr( @@ -294,7 +283,8 @@ pub enum EntryPointErr { NetworkErr(String), DecodeErr(String), CallDataErr(String), - UnknownErr(String), // describe impossible error. We should fix the codes here(or contract codes) if this occurs. + UnknownErr(String), /* describe impossible error. We should fix the codes here(or contract + * codes) if this occurs. */ } impl Display for EntryPointErr { @@ -306,18 +296,15 @@ impl Display for EntryPointErr { impl EntryPointErr { fn from_provider_err(err: &ProviderError) -> Result { match err { - ProviderError::JsonRpcClientError(err) => err - .as_error_response() - .map(Self::from_json_rpc_error) - .unwrap_or(Err(EntryPointErr::UnknownErr(format!( - "Unknown JSON-RPC client error: {err:?}" - )))), - ProviderError::HTTPError(err) => Err(EntryPointErr::NetworkErr(format!( - "Entry point HTTP error: {err:?}" - ))), - _ => Err(EntryPointErr::UnknownErr(format!( - "Unknown error in provider: {err:?}" - ))), + ProviderError::JsonRpcClientError(err) => { + err.as_error_response().map(Self::from_json_rpc_error).unwrap_or(Err( + EntryPointErr::UnknownErr(format!("Unknown JSON-RPC client error: {err:?}")), + )) + } + ProviderError::HTTPError(err) => { + Err(EntryPointErr::NetworkErr(format!("Entry point HTTP error: {err:?}"))) + } + _ => Err(EntryPointErr::UnknownErr(format!("Unknown error in provider: {err:?}"))), } } @@ -360,9 +347,7 @@ impl EntryPointErr { } } - Err(Self::UnknownErr(format!( - "Json rpc error {err:?} doesn't contain data field." - ))) + Err(Self::UnknownErr(format!("Json rpc error {err:?} doesn't contain data field."))) } fn from_middleware_err( @@ -376,9 +361,7 @@ impl EntryPointErr { return EntryPointErr::from_provider_err(err); } - Err(EntryPointErr::UnknownErr(format!( - "Unknown middleware error: {err:?}" - ))) + Err(EntryPointErr::UnknownErr(format!("Unknown middleware error: {err:?}"))) } } @@ -397,9 +380,7 @@ mod tests { let eth_client = Arc::new(Provider::try_from("http://127.0.0.1:8545").unwrap()); let ep = EntryPoint::>::new( eth_client.clone(), - "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - .parse() - .unwrap(), + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".parse().unwrap(), ); let max_priority_fee_per_gas = 1500000000_u64.into(); @@ -421,10 +402,7 @@ mod tests { let res = ep.simulate_validation(uo.clone()).await.unwrap(); - assert!(matches!( - res, - SimulateValidationResult::ValidationResult { .. }, - )); + assert!(matches!(res, SimulateValidationResult::ValidationResult { .. },)); let trace = ep.simulate_validation_trace(uo).await.unwrap(); diff --git a/crates/contracts/src/gen.rs b/crates/contracts/src/gen.rs index 8e19874b..9eef465b 100644 --- a/crates/contracts/src/gen.rs +++ b/crates/contracts/src/gen.rs @@ -8,14 +8,8 @@ use std::collections::HashMap; abigen!(AccountAPI, "$OUT_DIR/IAccount.sol/IAccount.json"); abigen!(EntryPointAPI, "$OUT_DIR/IEntryPoint.sol/IEntryPoint.json"); abigen!(PaymasterAPI, "$OUT_DIR/IPaymaster.sol/IPaymaster.json"); -abigen!( - SenderCreatorAPI, - "$OUT_DIR/SenderCreator.sol/SenderCreator.json" -); -abigen!( - StakeManagerAPI, - "$OUT_DIR/IStakeManager.sol/IStakeManager.json" -); +abigen!(SenderCreatorAPI, "$OUT_DIR/SenderCreator.sol/SenderCreator.json"); +abigen!(StakeManagerAPI, "$OUT_DIR/IStakeManager.sol/IStakeManager.json"); lazy_static! { pub static ref SELECTORS_NAMES: HashMap = { diff --git a/crates/contracts/src/utils.rs b/crates/contracts/src/utils.rs index 210f39ec..09405d4c 100644 --- a/crates/contracts/src/utils.rs +++ b/crates/contracts/src/utils.rs @@ -39,14 +39,12 @@ impl From for UserOperation { } pub fn parse_from_input_data(data: Bytes) -> Option> { - EntryPointAPICalls::decode(data) - .ok() - .and_then(|call| match call { - EntryPointAPICalls::HandleOps(ops) => { - Some(ops.ops.into_iter().map(|op| op.into()).collect()) - } - _ => None, - }) + EntryPointAPICalls::decode(data).ok().and_then(|call| match call { + EntryPointAPICalls::HandleOps(ops) => { + Some(ops.ops.into_iter().map(|op| op.into()).collect()) + } + _ => None, + }) } #[cfg(test)] diff --git a/crates/grpc/Cargo.toml b/crates/grpc/Cargo.toml index 3d08cd04..161fa994 100644 --- a/crates/grpc/Cargo.toml +++ b/crates/grpc/Cargo.toml @@ -6,37 +6,52 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler gRPC interfaces -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-4337) gRPC modules" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/grpc" [dependencies] +# workspace dependencies +silius-bundler = { workspace = true } +silius-contracts = { workspace = true } +silius-mempool = { workspace = true } +silius-p2p = { workspace = true } +silius-primitives = { workspace = true } + +# eth alloy-chains = { workspace = true } -arrayref = "0.3" -async-trait = { workspace = true } discv5 = { workspace = true } ethers = { workspace = true } -expanded-pathbuf = { workspace = true } -eyre = { workspace = true } -futures = "0.3.28" -libp2p-identity = "0.2.3" -parking_lot = { workspace = true } + +# grpc prost = "0.11" -serde_json = { workspace = true } -silius-bundler = { path = "../bundler" } -silius-contracts = { path = "../contracts" } -silius-p2p = { path = "../p2p" } -silius-primitives = { path = "../primitives" } -silius-uopool = { path = "../uopool" } -tokio = { workspace = true } tonic = { version = "0.8", default-features = false, features = [ "codegen", "prost", "transport", ] } + +# p2p +libp2p-identity = "0.2.3" + +# async +async-trait = { workspace = true } +futures = "0.3.28" +parking_lot = { workspace = true } + +# tokio +tokio = { workspace = true } + +# misc +arrayref = "0.3" +expanded-pathbuf = { workspace = true } +eyre = { workspace = true } +serde_json = { workspace = true } tracing = { workspace = true } [build-dependencies] +# grpc prost-build = "0.11" protobuf-src = "1.1.0" tonic-build = "0.8" diff --git a/crates/grpc/README.md b/crates/grpc/README.md new file mode 100644 index 00000000..5b112f52 --- /dev/null +++ b/crates/grpc/README.md @@ -0,0 +1,3 @@ +# silius-grpc + +TODO \ No newline at end of file diff --git a/crates/grpc/src/bundler.rs b/crates/grpc/src/bundler.rs index 590db648..dbfda106 100644 --- a/crates/grpc/src/bundler.rs +++ b/crates/grpc/src/bundler.rs @@ -1,13 +1,16 @@ -use crate::proto::bundler::*; -use crate::proto::uopool::GetSortedRequest; -use crate::uo_pool_client::UoPoolClient; +use crate::{ + proto::{bundler::*, uopool::GetSortedRequest}, + uo_pool_client::UoPoolClient, +}; use alloy_chains::Chain; use async_trait::async_trait; -use ethers::providers::Middleware; -use ethers::types::{Address, H256, U256}; +use ethers::{ + providers::Middleware, + types::{Address, H256, U256}, +}; use parking_lot::Mutex; use silius_bundler::Bundler; -use silius_primitives::{bundler::SendBundleMode, UserOperation, Wallet}; +use silius_primitives::{bundler::SendStrategy, UserOperation, Wallet}; use std::{net::SocketAddr, sync::Arc, time::Duration}; use tonic::{Request, Response, Status}; use tracing::{error, info}; @@ -34,24 +37,15 @@ where bundlers: Vec>, uopool_grpc_client: UoPoolClient, ) -> Self { - Self { - bundlers, - running: Arc::new(Mutex::new(false)), - uopool_grpc_client, - } + Self { bundlers, running: Arc::new(Mutex::new(false)), uopool_grpc_client } } async fn get_user_operations( uopool_grpc_client: &UoPoolClient, ep: &Address, ) -> eyre::Result> { - let req = Request::new(GetSortedRequest { - ep: Some((*ep).into()), - }); - let res = uopool_grpc_client - .clone() - .get_sorted_user_operations(req) - .await?; + let req = Request::new(GetSortedRequest { ep: Some((*ep).into()) }); + let res = uopool_grpc_client.clone().get_sorted_user_operations(req).await?; let uos: Vec = res.into_inner().uos.into_iter().map(|u| u.into()).collect(); Ok(uos) @@ -70,10 +64,7 @@ where // FIXME: Because currently the bundler support multiple bundler and // we don't have a way to know which bundler is the one that is - Ok(tx_hashes - .into_iter() - .next() - .expect("Must have at least one tx hash")) + Ok(tx_hashes.into_iter().next().expect("Must have at least one tx hash")) } pub fn stop_bundling(&self) { @@ -145,16 +136,12 @@ where match req.mode() { Mode::Manual => { self.stop_bundling(); - Ok(Response::new(SetModeResponse { - res: SetModeResult::Ok.into(), - })) + Ok(Response::new(SetModeResponse { res: SetModeResult::Ok.into() })) } Mode::Auto => { let int = req.interval; self.start_bundling(int); - Ok(Response::new(SetModeResponse { - res: SetModeResult::Ok.into(), - })) + Ok(Response::new(SetModeResponse { res: SetModeResult::Ok.into() })) } } } @@ -167,9 +154,7 @@ where .send_bundles() .await .map_err(|e| tonic::Status::internal(format!("Send bundle now with error: {e:?}")))?; - Ok(Response::new(SendBundleNowResponse { - res: Some(res.into()), - })) + Ok(Response::new(SendBundleNowResponse { res: Some(res.into()) })) } } @@ -184,7 +169,7 @@ pub fn bundler_service_run( min_balance: U256, bundle_interval: u64, uopool_grpc_client: UoPoolClient, - send_bundle_mode: SendBundleMode, + send_bundle_mode: SendStrategy, relay_endpoints: Option>, ) where M: Middleware + Clone + 'static, diff --git a/crates/grpc/src/lib.rs b/crates/grpc/src/lib.rs index 59fb1493..3ca53107 100644 --- a/crates/grpc/src/lib.rs +++ b/crates/grpc/src/lib.rs @@ -6,7 +6,5 @@ mod uopool; mod utils; pub use bundler::{bundler_service_run, BundlerService}; -pub use proto::bundler::*; -pub use proto::types::*; -pub use proto::uopool::*; +pub use proto::{bundler::*, types::*, uopool::*}; pub use uopool::{uopool_service_run, UoPoolService}; diff --git a/crates/grpc/src/proto.rs b/crates/grpc/src/proto.rs index 2b7313ac..8d5b3443 100644 --- a/crates/grpc/src/proto.rs +++ b/crates/grpc/src/proto.rs @@ -89,9 +89,7 @@ pub mod types { fn from(val: ethers::types::U256) -> Self { let mut bytes: [u8; 32] = [0; 32]; val.to_big_endian(bytes.as_mut()); - PbU256 { - data: prost::bytes::Bytes::copy_from_slice(&bytes), - } + PbU256 { data: prost::bytes::Bytes::copy_from_slice(&bytes) } } } @@ -342,24 +340,24 @@ pub mod uopool { } pub mod bundler { - use silius_primitives::BundlerMode as GrpcMode; + use silius_primitives::BundlerMode; tonic::include_proto!("bundler"); - impl From for GrpcMode { + impl From for BundlerMode { fn from(value: Mode) -> Self { match value { - Mode::Auto => Self::Auto, + Mode::Auto => Self::Auto(0), Mode::Manual => Self::Manual, } } } - impl From for Mode { - fn from(value: GrpcMode) -> Self { + impl From for Mode { + fn from(value: BundlerMode) -> Self { match value { - GrpcMode::Auto => Self::Auto, - GrpcMode::Manual => Self::Manual, + BundlerMode::Auto(_) => Self::Auto, + BundlerMode::Manual => Self::Manual, } } } diff --git a/crates/grpc/src/protos/bundler/bundler.proto b/crates/grpc/src/protos/bundler/bundler.proto index c5cfbd8f..e23e6b0f 100644 --- a/crates/grpc/src/protos/bundler/bundler.proto +++ b/crates/grpc/src/protos/bundler/bundler.proto @@ -12,7 +12,7 @@ enum Mode { message SetModeRequest { Mode mode = 1; - uint64 interval = 2; // if the mode is auto, bundle will be sent every interval seconds + uint64 interval = 2; } enum SetModeResult{ diff --git a/crates/grpc/src/uopool.rs b/crates/grpc/src/uopool.rs index c0a4e272..727c38cd 100644 --- a/crates/grpc/src/uopool.rs +++ b/crates/grpc/src/uopool.rs @@ -1,6 +1,8 @@ -use crate::proto::uopool::*; use crate::{ - proto::types::{GetChainIdResponse, GetSupportedEntryPointsResponse}, + proto::{ + types::{GetChainIdResponse, GetSupportedEntryPointsResponse}, + uopool::*, + }, utils::{parse_addr, parse_hash, parse_uo}, }; use alloy_chains::Chain; @@ -11,30 +13,25 @@ use ethers::{ types::{Address, U256}, }; use eyre::Result; -use futures::channel::mpsc::unbounded; -use futures::StreamExt; +use futures::{channel::mpsc::unbounded, StreamExt}; use libp2p_identity::{secp256k1, Keypair}; use parking_lot::RwLock; -use silius_p2p::config::Config; -use silius_p2p::enr::{build_enr, keypair_to_combined}; -use silius_p2p::network::{EntrypointChannels, Network}; -use silius_primitives::provider::BlockStream; -use silius_primitives::uopool::AddError; -use silius_primitives::UserOperation; -use silius_uopool::{ - mempool_id, validate::validator::StandardUserOperationValidator, MempoolId, - UoPool as UserOperationPool, UoPoolBuilder, +use silius_mempool::{ + mempool_id, validate::validator::StandardUserOperationValidator, HashSetOp, Mempool, MempoolId, + Reputation, ReputationEntryOp, SanityCheck, SimulationCheck, SimulationTraceCheck, + UoPool as UserOperationPool, UoPoolBuilder, UserOperationAct, UserOperationAddrAct, + UserOperationCodeHashAct, }; -use silius_uopool::{ - HashSetOp, Mempool, Reputation, ReputationEntryOp, SanityCheck, SimulationCheck, - SimulationTraceCheck, UserOperationAct, UserOperationAddrAct, UserOperationCodeHashAct, +use silius_p2p::{ + config::Config, + enr::{build_enr, keypair_to_combined}, + network::{EntrypointChannels, Network}, +}; +use silius_primitives::{mempool::AddError, provider::BlockStream, UserOperation}; +use std::{ + collections::HashMap, env, net::SocketAddr, os::unix::prelude::PermissionsExt, path::PathBuf, + str::FromStr, sync::Arc, time::Duration, }; -use std::collections::HashMap; -use std::env; -use std::os::unix::prelude::PermissionsExt; -use std::path::PathBuf; -use std::str::FromStr; -use std::{net::SocketAddr, sync::Arc, time::Duration}; use tonic::{Code, Request, Response, Status}; use tracing::{debug, error, info}; @@ -100,10 +97,7 @@ where .read() .get(&m_id) .map(|b| b.uopool()) - .ok_or(Status::new( - Code::Unavailable, - "User operation pool is not available", - )) + .ok_or(Status::new(Code::Unavailable, "User operation pool is not available")) } } @@ -170,9 +164,7 @@ where &self, _req: Request<()>, ) -> Result, Status> { - Ok(Response::new(GetChainIdResponse { - chain_id: self.chain.id(), - })) + Ok(Response::new(GetChainIdResponse { chain_id: self.chain.id() })) } async fn get_supported_entry_points( @@ -200,22 +192,18 @@ where let uopool = self.get_uopool(&ep)?; - Ok(Response::new( - match uopool.estimate_user_operation_gas(&uo).await { - Ok(gas) => EstimateUserOperationGasResponse { - res: EstimateUserOperationGasResult::Estimated as i32, - data: serde_json::to_string(&gas).map_err(|err| { - Status::internal(format!("Failed to serialize gas: {err}")) - })?, - }, - Err(err) => EstimateUserOperationGasResponse { - res: EstimateUserOperationGasResult::NotEstimated as i32, - data: serde_json::to_string(&err).map_err(|err| { - Status::internal(format!("Failed to serialize error: {err}")) - })?, - }, + Ok(Response::new(match uopool.estimate_user_operation_gas(&uo).await { + Ok(gas) => EstimateUserOperationGasResponse { + res: EstimateUserOperationGasResult::Estimated as i32, + data: serde_json::to_string(&gas) + .map_err(|err| Status::internal(format!("Failed to serialize gas: {err}")))?, }, - )) + Err(err) => EstimateUserOperationGasResponse { + res: EstimateUserOperationGasResult::NotEstimated as i32, + data: serde_json::to_string(&err) + .map_err(|err| Status::internal(format!("Failed to serialize error: {err}")))?, + }, + })) } async fn get_sorted_user_operations( @@ -318,9 +306,9 @@ where let ep = parse_addr(req.ep)?; let uopool = self.get_uopool(&ep)?; match uopool.get_all() { - Ok(uos) => Ok(Response::new(GetAllResponse { - uos: uos.into_iter().map(Into::into).collect(), - })), + Ok(uos) => { + Ok(Response::new(GetAllResponse { uos: uos.into_iter().map(Into::into).collect() })) + } Err(err) => Err(Status::unknown(format!("Internal error: {err:?}"))), } } @@ -356,11 +344,7 @@ where let uopool = self.get_uopool(&ep)?; Ok(Response::new(GetAllReputationResponse { - rep: uopool - .get_reputation() - .into_iter() - .map(Into::into) - .collect(), + rep: uopool.get_reputation().into_iter().map(Into::into).collect(), })) } @@ -494,9 +478,7 @@ where .expect("Creating key file directory failed"); std::fs::write( node_key_file.clone(), - keypair - .to_protobuf_encoding() - .expect("Discovery secret encoding failed"), + keypair.to_protobuf_encoding().expect("Discovery secret encoding failed"), ) .expect("Discovery secret writing failed"); std::fs::set_permissions(node_key_file, std::fs::Permissions::from_mode(0o600)) @@ -532,9 +514,7 @@ where for listen_addr in listen_addrs.into_iter() { info!("P2P node listened on {}", listen_addr); - p2p_network - .listen_on(listen_addr) - .expect("Listen on p2p network failed"); + p2p_network.listen_on(listen_addr).expect("Listen on p2p network failed"); } if bootnodes.is_empty() { diff --git a/crates/grpc/src/utils.rs b/crates/grpc/src/utils.rs index 8359e1cb..2accb152 100644 --- a/crates/grpc/src/utils.rs +++ b/crates/grpc/src/utils.rs @@ -19,9 +19,6 @@ pub fn parse_hash(h: Option) -> Result { pub fn parse_uo(uo: Option) -> Result { match uo { Some(uo) => Ok(uo.into()), - None => Err(Status::new( - Code::InvalidArgument, - "User operation is not valid", - )), + None => Err(Status::new(Code::InvalidArgument, "User operation is not valid")), } } diff --git a/crates/uopool/Cargo.toml b/crates/mempool/Cargo.toml similarity index 66% rename from crates/uopool/Cargo.toml rename to crates/mempool/Cargo.toml index 79373fc7..b97e65d0 100644 --- a/crates/uopool/Cargo.toml +++ b/crates/mempool/Cargo.toml @@ -1,37 +1,52 @@ [package] -name = "silius-uopool" +name = "silius-mempool" version = { workspace = true } authors = { workspace = true } edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler uopool implementation -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstractiono (ERC-4337) mempool implementation" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/mempool" [dependencies] +# workspace dependencies +silius-contracts = { workspace = true } +silius-primitives = { workspace = true } + +# eth alloy-chains = { workspace = true } +ethers = { workspace = true } + +# reth +reth-db = { git = "https://github.com/paradigmxyz/reth.git", rev = "aa6f2cb0610fb4fa0926b42cfed7f8ff51e0db8a" } +reth-libmdbx = { git = "https://github.com/paradigmxyz/reth.git", rev = "aa6f2cb0610fb4fa0926b42cfed7f8ff51e0db8a" } + +# async async-trait = { workspace = true } +futures = "0.3.28" +futures-util = { workspace = true } +parking_lot = { workspace = true } + +# tokio +tokio = { workspace = true } + +# misc bin-layout = "7.1.0" educe = { version = "0.4", features = ["Debug", "Default"] } enumset = "1.1.2" -ethers = { workspace = true } eyre = { workspace = true } -futures = "0.3.28" -futures-util = { workspace = true } page_size = "0.5.0" -parking_lot = { workspace = true } prost = "0.11" -reth-db = { git = "https://github.com/paradigmxyz/reth.git", rev = "aa6f2cb0610fb4fa0926b42cfed7f8ff51e0db8a" } -reth-libmdbx = { git = "https://github.com/paradigmxyz/reth.git", rev = "aa6f2cb0610fb4fa0926b42cfed7f8ff51e0db8a" } serde = "1" serde_json = { workspace = true } -silius-contracts = { path = "../contracts" } -silius-primitives = { path = "../primitives" } -tokio = { workspace = true } tracing = { workspace = true } [dev-dependencies] -silius-primitives = { path = "../primitives", features = ["test-utils"] } +# workspace dependencies +silius-primitives = { workspace = true, features = ["test-utils"] } + +# misc tempdir = "0.3.7" diff --git a/crates/uopool/README.md b/crates/mempool/README.md similarity index 97% rename from crates/uopool/README.md rename to crates/mempool/README.md index f718baf1..74d538a5 100644 --- a/crates/uopool/README.md +++ b/crates/mempool/README.md @@ -1,4 +1,4 @@ -# Silius UserOperation Pool +# silius-mempool The UserOperation alternative mempool implementation according to the [ERC-4337 specifications](https://eips.ethereum.org/EIPS/eip-4337#Alternative%20Mempools). diff --git a/crates/uopool/src/builder.rs b/crates/mempool/src/builder.rs similarity index 89% rename from crates/uopool/src/builder.rs rename to crates/mempool/src/builder.rs index 92788a46..3f0a8627 100644 --- a/crates/uopool/src/builder.rs +++ b/crates/mempool/src/builder.rs @@ -17,8 +17,7 @@ use futures::channel::mpsc::UnboundedSender; use futures_util::StreamExt; use silius_contracts::EntryPoint; use silius_primitives::{get_address, provider::BlockStream, UserOperation}; -use std::sync::Arc; -use std::time::Duration; +use std::{sync::Arc, time::Duration}; use tracing::warn; type StandardUoPool = @@ -88,20 +87,14 @@ where hash: H256, uopool: &mut StandardUoPool, ) -> eyre::Result<()> { - let txs = uopool - .entry_point - .eth_client() - .get_block_with_txs(hash) - .await? - .map(|b| b.transactions); + let txs = + uopool.entry_point.eth_client().get_block_with_txs(hash).await?.map(|b| b.transactions); if let Some(txs) = txs { for tx in txs { if tx.to == Some(uopool.entry_point.address()) { - let dec: Result<(Vec, Address), _> = uopool - .entry_point - .entry_point_api() - .decode("handleOps", tx.input); + let dec: Result<(Vec, Address), _> = + uopool.entry_point.entry_point_api().decode("handleOps", tx.input); if let Ok((uos, _)) = dec { uopool.remove_user_operations( @@ -117,12 +110,9 @@ where for uo in uos { // update reputations - uopool - .reputation - .increment_included(&uo.sender) - .map_err(|e| { - format_err!("Failed to increment sender reputation: {:?}", e) - })?; + uopool.reputation.increment_included(&uo.sender).map_err(|e| { + format_err!("Failed to increment sender reputation: {:?}", e) + })?; if let Some(addr) = get_address(&uo.paymaster_and_data) { uopool.reputation.increment_included(&addr).map_err(|e| { diff --git a/crates/uopool/src/database/env.rs b/crates/mempool/src/database/env.rs similarity index 82% rename from crates/uopool/src/database/env.rs rename to crates/mempool/src/database/env.rs index d3e530bd..08c5bd44 100644 --- a/crates/uopool/src/database/env.rs +++ b/crates/mempool/src/database/env.rs @@ -24,19 +24,11 @@ impl<'a, E: EnvironmentKind> DatabaseGAT<'a> for Env { impl Database for Env { fn tx(&self) -> Result<>::TX, Error> { - Ok(Tx::new( - self.inner - .begin_ro_txn() - .map_err(|e| Error::InitTransaction(e.into()))?, - )) + Ok(Tx::new(self.inner.begin_ro_txn().map_err(|e| Error::InitTransaction(e.into()))?)) } fn tx_mut(&self) -> Result<>::TXMut, Error> { - Ok(Tx::new( - self.inner - .begin_rw_txn() - .map_err(|e| Error::InitTransaction(e.into()))?, - )) + Ok(Tx::new(self.inner.begin_rw_txn().map_err(|e| Error::InitTransaction(e.into()))?)) } } @@ -85,9 +77,7 @@ impl Env { page_size: Some(PageSize::Set(default_page_size())), }) .set_flags(EnvironmentFlags { - mode: Mode::ReadWrite { - sync_mode: SyncMode::Durable, - }, + mode: Mode::ReadWrite { sync_mode: SyncMode::Durable }, no_rdahead: true, // TODO: reevaluate coalesce: true, ..Default::default() @@ -100,10 +90,7 @@ impl Env { /// Creates all the defined tables, if necessary pub fn create_tables(&self) -> Result<(), Error> { - let tx = self - .inner - .begin_rw_txn() - .map_err(|e| Error::InitTransaction(e.into()))?; + let tx = self.inner.begin_rw_txn().map_err(|e| Error::InitTransaction(e.into()))?; for (table_type, table) in TABLES { let flags = match table_type { @@ -111,8 +98,7 @@ impl Env { TableType::DupSort => DatabaseFlags::DUP_SORT, }; - tx.create_db(Some(table), flags) - .map_err(|e| Error::TableCreation(e.into()))?; + tx.create_db(Some(table), flags).map_err(|e| Error::TableCreation(e.into()))?; } tx.commit().map_err(|e| Error::Commit(e.into()))?; diff --git a/crates/uopool/src/database/mempool.rs b/crates/mempool/src/database/mempool.rs similarity index 94% rename from crates/uopool/src/database/mempool.rs rename to crates/mempool/src/database/mempool.rs index 0e00c710..0e7d8e6b 100644 --- a/crates/uopool/src/database/mempool.rs +++ b/crates/mempool/src/database/mempool.rs @@ -1,9 +1,11 @@ -use super::utils::{WrapCodeHash, WrapCodeHashVec, WrapUserOpSet}; -use super::DatabaseTable; use super::{ env::DBError, tables::{CodeHashes, UserOperations, UserOperationsByEntity, UserOperationsBySender}, - utils::{WrapAddress, WrapUserOperation, WrapUserOperationHash}, + utils::{ + WrapAddress, WrapCodeHash, WrapCodeHashVec, WrapUserOpSet, WrapUserOperation, + WrapUserOperationHash, + }, + DatabaseTable, }; use crate::mempool::{ AddRemoveUserOp, AddRemoveUserOpHash, ClearOp, MempoolError, UserOperationAddrOp, @@ -179,11 +181,8 @@ impl UserOperationCodeHashOp for DatabaseTable>() - .into(); + let wrap_hashes: WrapCodeHashVec = + hashes.into_iter().map(Into::into).collect::>().into(); tx.put::(uo_hash_wrap, wrap_hashes)?; tx.commit()?; Ok(()) @@ -196,10 +195,7 @@ impl UserOperationCodeHashOp for DatabaseTable = hashes.into(); - hashes - .into_iter() - .map(Into::into) - .collect::>() + hashes.into_iter().map(Into::into).collect::>() }) .unwrap_or(vec![])) } @@ -257,8 +253,7 @@ mod tests { let dir = TempDir::new("test-silius-db").unwrap(); let env = init_env::(dir.into_path()).unwrap(); - env.create_tables() - .expect("Create mdbx database tables failed"); + env.create_tables().expect("Create mdbx database tables failed"); let env = Arc::new(env); let uo_ops: DatabaseTable = DatabaseTable::new(env.clone()); let uo_ops_sender: DatabaseTable = diff --git a/crates/uopool/src/database/mod.rs b/crates/mempool/src/database/mod.rs similarity index 76% rename from crates/uopool/src/database/mod.rs rename to crates/mempool/src/database/mod.rs index 4bb8327a..d72e74c5 100644 --- a/crates/uopool/src/database/mod.rs +++ b/crates/mempool/src/database/mod.rs @@ -1,4 +1,5 @@ -//! The database implementation of the [Mempool](crate::mempool::Mempool) trait. Primarily used for storing mempool information in a local database. +//! The database implementation of the [Mempool](crate::mempool::Mempool) trait. Primarily used for +//! storing mempool information in a local database. pub use self::env::DBError; use self::env::Env; use reth_libmdbx::EnvironmentKind; @@ -25,18 +26,12 @@ pub struct DatabaseTable { impl Clone for DatabaseTable { fn clone(&self) -> Self { - Self { - env: self.env.clone(), - _table: std::marker::PhantomData, - } + Self { env: self.env.clone(), _table: std::marker::PhantomData } } } impl DatabaseTable { pub fn new(env: Arc>) -> Self { - Self { - env, - _table: std::marker::PhantomData, - } + Self { env, _table: std::marker::PhantomData } } } diff --git a/crates/uopool/src/database/reputation.rs b/crates/mempool/src/database/reputation.rs similarity index 96% rename from crates/uopool/src/database/reputation.rs rename to crates/mempool/src/database/reputation.rs index f23954a6..bdb87f4a 100644 --- a/crates/uopool/src/database/reputation.rs +++ b/crates/mempool/src/database/reputation.rs @@ -92,7 +92,7 @@ mod tests { }; use ethers::types::{Address, U256}; use reth_libmdbx::WriteMap; - use silius_primitives::consts::reputation::{ + use silius_primitives::constants::validation::reputation::{ BAN_SLACK, MIN_INCLUSION_RATE_DENOMINATOR, THROTTLING_SLACK, }; use std::{collections::HashSet, sync::Arc}; @@ -103,8 +103,7 @@ mod tests { let dir = TempDir::new("test-silius-db").unwrap(); let env = init_env::(dir.into_path()).unwrap(); - env.create_tables() - .expect("Create mdbx database tables failed"); + env.create_tables().expect("Create mdbx database tables failed"); let env = Arc::new(env); let entry: DatabaseTable = DatabaseTable::new(env.clone()); let reputation = Reputation::new( diff --git a/crates/uopool/src/database/tables.rs b/crates/mempool/src/database/tables.rs similarity index 100% rename from crates/uopool/src/database/tables.rs rename to crates/mempool/src/database/tables.rs diff --git a/crates/uopool/src/database/utils.rs b/crates/mempool/src/database/utils.rs similarity index 97% rename from crates/uopool/src/database/utils.rs rename to crates/mempool/src/database/utils.rs index 3fd817b4..e6c62f8c 100644 --- a/crates/uopool/src/database/utils.rs +++ b/crates/mempool/src/database/utils.rs @@ -9,10 +9,10 @@ use serde::{Deserialize, Serialize}; use silius_primitives::{ reputation::ReputationEntry, simulation::CodeHash, UserOperation, UserOperationHash, }; -use std::collections::HashSet; -use std::fmt::Debug; +use std::{collections::HashSet, fmt::Debug}; -/// Cretaes a compression & decompression wrapper for a type(20 or 32 bytes) that is used in the database. +/// Creates a compression & decompression wrapper for a type(20 or 32 bytes) that is used in the +/// database. macro_rules! construct_wrap_hash { ($type:ty, $name:ident, $n_bytes:expr ) => { #[derive( diff --git a/crates/uopool/src/lib.rs b/crates/mempool/src/lib.rs similarity index 78% rename from crates/uopool/src/lib.rs rename to crates/mempool/src/lib.rs index 128f3230..a90de607 100644 --- a/crates/uopool/src/lib.rs +++ b/crates/mempool/src/lib.rs @@ -11,10 +11,14 @@ mod utils; pub mod validate; pub use builder::UoPoolBuilder; -pub use database::tables::{ - CodeHashes, EntitiesReputation, UserOperations, UserOperationsByEntity, UserOperationsBySender, +pub use database::{ + init_env, + tables::{ + CodeHashes, EntitiesReputation, UserOperations, UserOperationsByEntity, + UserOperationsBySender, + }, + DBError, DatabaseTable, WriteMap, }; -pub use database::{init_env, DBError, DatabaseTable, WriteMap}; pub use mempool::{ mempool_id, AddRemoveUserOp, AddRemoveUserOpHash, Mempool, MempoolId, UserOperationAct, UserOperationAddrAct, UserOperationAddrOp, UserOperationCodeHashAct, UserOperationCodeHashOp, diff --git a/crates/uopool/src/memory/mempool.rs b/crates/mempool/src/memory/mempool.rs similarity index 100% rename from crates/uopool/src/memory/mempool.rs rename to crates/mempool/src/memory/mempool.rs diff --git a/crates/uopool/src/memory/mod.rs b/crates/mempool/src/memory/mod.rs similarity index 100% rename from crates/uopool/src/memory/mod.rs rename to crates/mempool/src/memory/mod.rs diff --git a/crates/uopool/src/memory/reputation.rs b/crates/mempool/src/memory/reputation.rs similarity index 94% rename from crates/uopool/src/memory/reputation.rs rename to crates/mempool/src/memory/reputation.rs index 19ebf927..7705db0d 100644 --- a/crates/uopool/src/memory/reputation.rs +++ b/crates/mempool/src/memory/reputation.rs @@ -59,15 +59,15 @@ impl ReputationEntryOp for HashMap { } #[cfg(test)] mod tests { - use std::collections::{HashMap, HashSet}; - + use crate::{utils::tests::reputation_test_case, Reputation}; use ethers::types::{Address, U256}; use silius_primitives::{ - consts::reputation::{BAN_SLACK, MIN_INCLUSION_RATE_DENOMINATOR, THROTTLING_SLACK}, + constants::validation::reputation::{ + BAN_SLACK, MIN_INCLUSION_RATE_DENOMINATOR, THROTTLING_SLACK, + }, reputation::ReputationEntry, }; - - use crate::{utils::tests::reputation_test_case, Reputation}; + use std::collections::{HashMap, HashSet}; #[tokio::test] async fn memory_reputation() { diff --git a/crates/uopool/src/mempool.rs b/crates/mempool/src/mempool.rs similarity index 95% rename from crates/uopool/src/mempool.rs rename to crates/mempool/src/mempool.rs index 8ee69e43..09a23ee6 100644 --- a/crates/uopool/src/mempool.rs +++ b/crates/mempool/src/mempool.rs @@ -1,5 +1,4 @@ -use std::sync::Arc; - +use crate::DBError; use ethers::{ abi::AbiEncode, types::{Address, H256, U256}, @@ -7,8 +6,7 @@ use ethers::{ }; use parking_lot::RwLock; use silius_primitives::{simulation::CodeHash, UserOperation, UserOperationHash}; - -use crate::DBError; +use std::sync::Arc; pub type MempoolId = H256; @@ -67,7 +65,8 @@ pub trait AddRemoveUserOp { /// * `uo_hash` - The hash of the [UserOperation](UserOperation) to remove /// /// # Returns - /// * `Ok(bool)` - true if the [UserOperation](UserOperation) was removed, false means it was not found + /// * `Ok(bool)` - true if the [UserOperation](UserOperation) was removed, false means it was + /// not found /// * `Err(MempoolError)` - If there are some internal errors fn remove_by_uo_hash(&mut self, uo_hash: &UserOperationHash) -> Result; } @@ -162,8 +161,8 @@ pub trait UserOperationOp { /// /// # Returns /// - /// Returns `Ok(Vec)` containing all user operations sorted in the specified order, - /// or an `Err(MempoolError)` if an error occurs. + /// Returns `Ok(Vec)` containing all user operations sorted in the specified + /// order, or an `Err(MempoolError)` if an error occurs. fn get_sorted(&self) -> Result, MempoolError>; /// Retrieves all user operations. @@ -239,7 +238,8 @@ pub trait UserOperationCodeHashOp { /// /// - If the user operation hash has associated code hashes, `Ok(true)` is returned. /// - If the user operation hash does not have associated code hashes, `Ok(false)` is returned. - /// - If an error occurs during the operation, an `Err` variant is returned with a `MempoolError`. + /// - If an error occurs during the operation, an `Err` variant is returned with a + /// `MempoolError`. fn has_code_hashes(&self, uo_hash: &UserOperationHash) -> Result; /// Sets the code hashes for the given user operation hash in the memory pool. @@ -254,14 +254,16 @@ pub trait UserOperationCodeHashOp { /// Returns a `Result` indicating the success or failure of the operation. /// /// - If the code hashes are successfully set, `Ok(())` is returned. - /// - If an error occurs during the operation, an `Err` variant is returned with a `MempoolError`. + /// - If an error occurs during the operation, an `Err` variant is returned with a + /// `MempoolError`. fn set_code_hashes( &mut self, uo_hash: &UserOperationHash, hashes: Vec, ) -> Result<(), MempoolError>; - /// Retrieves the code hashes associated with the given user operation hash from the memory pool. + /// Retrieves the code hashes associated with the given user operation hash from the memory + /// pool. /// /// # Arguments /// @@ -271,8 +273,10 @@ pub trait UserOperationCodeHashOp { /// /// Returns a `Result` containing the code hashes associated with the user operation hash. /// - /// - If the code hashes are successfully retrieved, `Ok(Vec)` is returned with the code hashes. - /// - If an error occurs during the operation, an `Err` variant is returned with a `MempoolError`. + /// - If the code hashes are successfully retrieved, `Ok(Vec)` is returned with the + /// code hashes. + /// - If an error occurs during the operation, an `Err` variant is returned with a + /// `MempoolError`. fn get_code_hashes(&self, uo_hash: &UserOperationHash) -> Result, MempoolError>; /// Removes the code hashes associated with the given user operation hash from the memory pool. @@ -287,7 +291,8 @@ pub trait UserOperationCodeHashOp { /// /// - If the code hashes are successfully removed, `Ok(true)` is returned. /// - If the user operation hash does not have associated code hashes, `Ok(false)` is returned. - /// - If an error occurs during the operation, an `Err` variant is returned with a `MempoolError`. + /// - If an error occurs during the operation, an `Err` variant is returned with a + /// `MempoolError`. fn remove_code_hashes(&mut self, uo_hash: &UserOperationHash) -> Result; } @@ -442,8 +447,7 @@ where uo_hash: &UserOperationHash, hashes: Vec, ) -> Result<(), MempoolError> { - self.user_operations_code_hashes - .set_code_hashes(uo_hash, hashes) + self.user_operations_code_hashes.set_code_hashes(uo_hash, hashes) } pub fn get_code_hashes( &self, @@ -462,21 +466,17 @@ where self.user_operations.remove_by_uo_hash(uo_hash)?; - self.user_operations_by_sender - .remove_uo_hash(&sender, uo_hash)?; + self.user_operations_by_sender.remove_uo_hash(&sender, uo_hash)?; if let Some(factory) = factory { - self.user_operations_by_entity - .remove_uo_hash(&factory, uo_hash)?; + self.user_operations_by_entity.remove_uo_hash(&factory, uo_hash)?; } if let Some(paymaster) = paymaster { - self.user_operations_by_entity - .remove_uo_hash(&paymaster, uo_hash)?; + self.user_operations_by_entity.remove_uo_hash(&paymaster, uo_hash)?; } - self.user_operations_code_hashes - .remove_code_hashes(uo_hash)?; + self.user_operations_code_hashes.remove_code_hashes(uo_hash)?; Ok(true) } diff --git a/crates/uopool/src/reputation.rs b/crates/mempool/src/reputation.rs similarity index 96% rename from crates/uopool/src/reputation.rs rename to crates/mempool/src/reputation.rs index 7ae77feb..aa2b1396 100644 --- a/crates/uopool/src/reputation.rs +++ b/crates/mempool/src/reputation.rs @@ -1,3 +1,4 @@ +use crate::{mempool::ClearOp, DBError}; use ethers::types::{Address, Bytes, U256}; use parking_lot::RwLock; use silius_primitives::{ @@ -6,8 +7,6 @@ use silius_primitives::{ }; use std::{fmt::Debug, ops::Deref, sync::Arc}; -use crate::{mempool::ClearOp, DBError}; - #[derive(Debug)] pub enum ReputationOpError { DBError(DBError), @@ -105,7 +104,8 @@ pub trait ReputationEntryOp: ClearOp + Sync + Send { /// # Returns /// /// Returns `Ok(Some(previous_entry))` if there was a previous entry for the address, - /// `Ok(None)` if there was no previous entry, or an `Err` if an error occurred during the operation. + /// `Ok(None)` if there was no previous entry, or an `Err` if an error occurred during the + /// operation. fn set_entry( &mut self, addr: &Address, @@ -128,7 +128,8 @@ pub trait ReputationEntryOp: ClearOp + Sync + Send { /// /// # Returns /// - /// Returns `Ok(())` if the update was successful, or an `Err` if an error occurred during the update. + /// Returns `Ok(())` if the update was successful, or an `Err` if an error occurred during the + /// update. fn update(&mut self) -> Result<(), ReputationOpError>; /// Retrieves all reputation entries. @@ -265,10 +266,7 @@ where /// * `Err(ReputationError::NotFound)` if the address does not exist pub fn get(&self, addr: &Address) -> Result { if let Some(ent) = self.entities.get_entry(addr)? { - Ok(ReputationEntry { - status: self.get_status(addr)?, - ..ent.clone() - }) + Ok(ReputationEntry { status: self.get_status(addr)?, ..ent.clone() }) } else { Ok(ReputationEntry::default_with_addr(*addr)) } @@ -291,7 +289,8 @@ where Ok(()) } - /// Increases the number of times an entity successfully inlucdes a [UserOperation](UserOperation) in a block + /// Increases the number of times an entity successfully inlucdes a + /// [UserOperation](UserOperation) in a block /// /// # Arguments /// * `addr` - The address to increment @@ -509,9 +508,10 @@ where .collect()) } - // Try to get the reputation status from a sequence of bytes which the first 20 bytes should be the address - // This is useful in getting the reputation directly from paymaster_and_data field and init_code field in user operation. - // If the address is not found in the first 20 bytes, it would return ReputationStatus::OK directly. + // Try to get the reputation status from a sequence of bytes which the first 20 bytes should be + // the address This is useful in getting the reputation directly from paymaster_and_data + // field and init_code field in user operation. If the address is not found in the first 20 + // bytes, it would return ReputationStatus::OK directly. pub fn get_status_from_bytes( &self, bytes: &Bytes, diff --git a/crates/uopool/src/uopool.rs b/crates/mempool/src/uopool.rs similarity index 78% rename from crates/uopool/src/uopool.rs rename to crates/mempool/src/uopool.rs index ed55e3c2..6ceaef41 100644 --- a/crates/uopool/src/uopool.rs +++ b/crates/mempool/src/uopool.rs @@ -24,20 +24,22 @@ use silius_contracts::{ EntryPoint, }; use silius_primitives::{ - consts::reputation::THROTTLED_ENTITY_BUNDLE_COUNT, + constants::validation::reputation::THROTTLED_ENTITY_BUNDLE_COUNT, get_address, + mempool::{AddError, ValidationError}, reputation::{ReputationEntry, ReputationError, StakeInfo, StakeInfoResponse, Status}, sanity::SanityCheckError, simulation::SimulationCheckError, - uopool::{AddError, ValidationError}, UserOperation, UserOperationByHash, UserOperationGasEstimation, UserOperationHash, UserOperationReceipt, }; use std::collections::{HashMap, HashSet}; use tracing::{debug, error, info, trace}; -/// The alternative mempool pool implementation that provides functionalities to add, remove, validate, and serves data requests from the [RPC API](EthApiServer). -/// Architecturally, the [UoPool](UoPool) is the backend service managed by the [UoPoolService](UoPoolService) and serves requests from the [RPC API](EthApiServer). +/// The alternative mempool pool implementation that provides functionalities to add, remove, +/// validate, and serves data requests from the [RPC API](EthApiServer). Architecturally, the +/// [UoPool](UoPool) is the backend service managed by the [UoPoolService](UoPoolService) and serves +/// requests from the [RPC API](EthApiServer). pub struct UoPool where T: UserOperationAct, @@ -83,8 +85,8 @@ where /// `mempool` - The [MempoolBox](MempoolBox) is a [Boxed pointer](https://doc.rust-lang.org/std/boxed/struct.Box.html) to a [Mempool](Mempool) object /// `reputation` - The [ReputationBox](ReputationBox) is a [Boxed pointer](https://doc.rust-lang.org/std/boxed/struct.Box.html) to a [ReputationEntry](ReputationEntry) object /// `eth_client` - The Ethereum client [Middleware](ethers::providers::Middleware) - /// `max_verification_gas` - The maximum gas limit for [UserOperation](UserOperation) gas verification. - /// `chain` - The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID + /// `max_verification_gas` - The maximum gas limit for [UserOperation](UserOperation) gas + /// verification. `chain` - The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID /// /// # Returns /// `Self` - The [UoPool](UoPool) object @@ -165,7 +167,8 @@ where self.reputation.clear(); } - /// Validates a single [UserOperation](UserOperation) and returns the validation outcome by calling [UserOperationValidator::validate_user_operation](UserOperationValidator::validate_user_operation) + /// Validates a single [UserOperation](UserOperation) and returns the validation outcome by + /// calling [UserOperationValidator::validate_user_operation](UserOperationValidator::validate_user_operation) /// /// # Arguments /// `uo` - The [UserOperation](UserOperation) to validate @@ -181,20 +184,25 @@ where uo, &self.mempool, &self.reputation, - UserOperationValidatorMode::Sanity - | UserOperationValidatorMode::Simulation - | UserOperationValidatorMode::SimulationTrace, + UserOperationValidatorMode::Sanity | + UserOperationValidatorMode::Simulation | + UserOperationValidatorMode::SimulationTrace, ) .await } /// Adds a single validated user operation into the pool - /// Indirectly invoked by [EthApiServer::send_user_operation](EthApiServer::send_user_operation) via [UoPoolService::add](UoPoolService::add) to add a [UserOperation](UserOperation) into the mempool - /// The function first validates the [UserOperation](UserOperation) by calling [UoPool::validate_user_operation](UoPool::validate_user_operation). If [UserOperation](UserOperation) passes the validation, then adds it into the mempool by calling [Mempool::add](Mempool::add). + /// Indirectly invoked by [EthApiServer::send_user_operation](EthApiServer::send_user_operation) + /// via [UoPoolService::add](UoPoolService::add) to add a [UserOperation](UserOperation) into + /// the mempool The function first validates the [UserOperation](UserOperation) by calling + /// [UoPool::validate_user_operation](UoPool::validate_user_operation). If + /// [UserOperation](UserOperation) passes the validation, then adds it into the mempool by + /// calling [Mempool::add](Mempool::add). /// /// # Arguments /// `uo` - The [UserOperation](UserOperation) to add - /// `res` - The [UserOperationValidationOutcome](UserOperationValidationOutcome) of the validation + /// `res` - The [UserOperationValidationOutcome](UserOperationValidationOutcome) of the + /// validation /// /// # Returns /// `Result` - The hash of the added [UserOperation](UserOperation) @@ -223,11 +231,7 @@ where sd.unbounded_send((uo.clone(), res.verified_block)) .expect("Failed to send user operation to publish channel") }; - match self.mempool.add( - uo.clone(), - &self.entry_point.address(), - &self.chain.id().into(), - ) { + match self.mempool.add(uo.clone(), &self.entry_point.address(), &self.chain.id().into()) { Ok(uo_hash) => { // TODO: find better way to do it atomically if let Some(code_hashes) = res.code_hashes { @@ -242,33 +246,26 @@ where // update reputation self.reputation .increment_seen(&uo.sender) - .map_err(|e| AddError::MempoolError { - message: format!("{e:?}"), - })?; + .map_err(|e| AddError::MempoolError { message: format!("{e:?}") })?; if let Some(f_addr) = get_address(&uo.init_code) { - self.reputation.increment_seen(&f_addr).map_err(|e| { - AddError::MempoolError { - message: format!("{e:?}"), - } - })?; + self.reputation + .increment_seen(&f_addr) + .map_err(|e| AddError::MempoolError { message: format!("{e:?}") })?; } if let Some(p_addr) = get_address(&uo.paymaster_and_data) { - self.reputation.increment_seen(&p_addr).map_err(|e| { - AddError::MempoolError { - message: format!("{e:?}"), - } - })?; + self.reputation + .increment_seen(&p_addr) + .map_err(|e| AddError::MempoolError { message: format!("{e:?}") })?; } Ok(uo_hash) } - Err(e) => Err(AddError::MempoolError { - message: format!("{e:?}"), - }), + Err(e) => Err(AddError::MempoolError { message: format!("{e:?}") }), } } - /// Sorts the [UserOperations](UserOperation) in the mempool by calling the [Mempool::get_sorted](Mempool::get_sorted) function + /// Sorts the [UserOperations](UserOperation) in the mempool by calling the + /// [Mempool::get_sorted](Mempool::get_sorted) function /// /// # Returns /// `Result, eyre::Error>` - The sorted [UserOperations](UserOperation) @@ -277,8 +274,11 @@ where } /// Bundles an array of [UserOperations](UserOperation) - /// The function first checks the reputations of the entiries, then validate each [UserOperation](UserOperation) by calling [UoPool::validate_user_operation](UoPool::validate_user_operation). - /// If the [UserOperations](UserOperation) passes the validation, push it into the `uos_valid` array. + /// The function first checks the reputations of the entiries, then validate each + /// [UserOperation](UserOperation) by calling + /// [UoPool::validate_user_operation](UoPool::validate_user_operation). + /// If the [UserOperations](UserOperation) passes the validation, push it into the `uos_valid` + /// array. /// /// # Arguments /// `uos` - An array of [UserOperations](UserOperation) to bundle @@ -308,26 +308,16 @@ where let f_opt = get_address(&uo.init_code.0); let p_st = Status::from( - self.reputation - .get_status_from_bytes(&uo.paymaster_and_data) - .map_err(|err| { - format_err!("Error getting reputation status with error: {err:?}") - })?, - ); - let f_st = Status::from( - self.reputation - .get_status_from_bytes(&uo.init_code) - .map_err(|err| { - format_err!("Error getting reputation status with error: {err:?}") - })?, + self.reputation.get_status_from_bytes(&uo.paymaster_and_data).map_err(|err| { + format_err!("Error getting reputation status with error: {err:?}") + })?, ); + let f_st = Status::from(self.reputation.get_status_from_bytes(&uo.init_code).map_err( + |err| format_err!("Error getting reputation status with error: {err:?}"), + )?); - let p_c = p_opt - .map(|p| staked_entity_c.get(&p).cloned().unwrap_or(0)) - .unwrap_or(0); - let f_c = f_opt - .map(|f| staked_entity_c.get(&f).cloned().unwrap_or(0)) - .unwrap_or(0); + let p_c = p_opt.map(|p| staked_entity_c.get(&p).cloned().unwrap_or(0)).unwrap_or(0); + let f_c = f_opt.map(|f| staked_entity_c.get(&f).cloned().unwrap_or(0)).unwrap_or(0); match (p_st, f_st) { (Status::BANNED, _) | (_, Status::BANNED) => { @@ -353,14 +343,11 @@ where &uo, &self.mempool, &self.reputation, - UserOperationValidatorMode::Simulation - | UserOperationValidatorMode::SimulationTrace, + UserOperationValidatorMode::Simulation | + UserOperationValidatorMode::SimulationTrace, ) .await; - debug!( - "Second validation for userop {:?} result: {:?}", - uo_hash, val_out - ); + debug!("Second validation for userop {:?} result: {:?}", uo_hash, val_out); match val_out { Ok(val_out) => { @@ -378,10 +365,9 @@ where // TODO // it would be better to use estimate_gas instead of call_gas_limit - // The result of call_gas_limit is usesally higher and less user op would be included - let gas_cost = val_out - .verification_gas_limit - .saturating_add(uo.call_gas_limit); + // The result of call_gas_limit is usesally higher and less user op would be + // included + let gas_cost = val_out.verification_gas_limit.saturating_add(uo.call_gas_limit); let gas_total_new = gas_total.saturating_add(gas_cost); if gas_total_new.gt(&self.max_verification_gas) { break; @@ -401,18 +387,12 @@ where continue; } - staked_entity_c - .entry(p) - .and_modify(|c| *c += 1) - .or_insert(1); + staked_entity_c.entry(p).and_modify(|c| *c += 1).or_insert(1); paymaster_dep.insert(p, balance.saturating_sub(val_out.pre_fund)); } if let Some(f) = f_opt { - staked_entity_c - .entry(f) - .and_modify(|c| *c += 1) - .or_insert(1); + staked_entity_c.entry(f).and_modify(|c| *c += 1).or_insert(1); } gas_total = gas_total_new; @@ -445,19 +425,19 @@ where .get_block(BlockNumber::Latest) .await? .ok_or(format_err!("No block found"))?; - block - .base_fee_per_gas - .ok_or(format_err!("No base fee found")) + block.base_fee_per_gas.ok_or(format_err!("No base fee found")) } - /// Estimates the `verification_gas_limit`, `call_gas_limit` and `pre_verification_gas` for a user operation. - /// The function is indirectly invoked by the `estimate_user_operation_gas` JSON RPC method. + /// Estimates the `verification_gas_limit`, `call_gas_limit` and `pre_verification_gas` for a + /// user operation. The function is indirectly invoked by the `estimate_user_operation_gas` + /// JSON RPC method. /// /// # Arguments /// * `uo` - The [UserOperation](UserOperation) to estimate the gas for. /// /// # Returns - /// `Result` - The gas estimation result, which includes the `verification_gas_limit`, `call_gas_limit` and `pre_verification_gas`. + /// `Result` - The gas estimation result, + /// which includes the `verification_gas_limit`, `call_gas_limit` and `pre_verification_gas`. pub async fn estimate_user_operation_gas( &self, uo: &UserOperation, @@ -472,49 +452,40 @@ where ) .await .map_err(|err| match err { - ValidationError::Sanity(_) => SimulationCheckError::UnknownError { - message: "Unknown error".to_string(), - }, + ValidationError::Sanity(_) => { + SimulationCheckError::UnknownError { message: "Unknown error".to_string() } + } ValidationError::Simulation(err) => err, })?; match self.entry_point.simulate_execution(uo.clone()).await { Ok(_) => {} - Err(err) => { - return Err(SimulationCheckError::Execution { - message: err.to_string(), - }) - } + Err(err) => return Err(SimulationCheckError::Execution { message: err.to_string() }), } let exec_res = match self.entry_point.simulate_handle_op(uo.clone()).await { Ok(res) => res, Err(err) => { return Err(match err { - EntryPointErr::FailedOp(err) => SimulationCheckError::Execution { - message: err.to_string(), - }, - EntryPointErr::RevertError(err) => SimulationCheckError::Execution { - message: err.to_string(), - }, - _ => SimulationCheckError::UnknownError { - message: format!("{err:?}"), - }, + EntryPointErr::FailedOp(err) => { + SimulationCheckError::Execution { message: err.to_string() } + } + EntryPointErr::RevertError(err) => { + SimulationCheckError::Execution { message: err.to_string() } + } + _ => SimulationCheckError::UnknownError { message: format!("{err:?}") }, }) } }; - let base_fee_per_gas = - self.base_fee_per_gas() - .await - .map_err(|err| SimulationCheckError::UnknownError { - message: err.to_string(), - })?; + let base_fee_per_gas = self + .base_fee_per_gas() + .await + .map_err(|err| SimulationCheckError::UnknownError { message: err.to_string() })?; let call_gas_limit = calculate_call_gas_limit( exec_res.paid, exec_res.pre_op_gas, - uo.max_fee_per_gas - .min(uo.max_priority_fee_per_gas + base_fee_per_gas), + uo.max_fee_per_gas.min(uo.max_priority_fee_per_gas + base_fee_per_gas), ); Ok(UserOperationGasEstimation { @@ -524,13 +495,15 @@ where }) } - /// Filters the events logged from the [EntryPoint](EntryPoint) contract for a given user operation hash. + /// Filters the events logged from the [EntryPoint](EntryPoint) contract for a given user + /// operation hash. /// /// # Arguments /// * `uo_hash` - The [UserOperationHash](UserOperationHash) to filter the events for. /// /// # Returns - /// `Result, eyre::Error>` - The filtered event, if any. + /// `Result, eyre::Error>` - The filtered event, if + /// any. pub async fn get_user_operation_event_meta( &self, uo_hash: &UserOperationHash, @@ -595,7 +568,8 @@ where /// The function is indirectly invoked by the `get_user_operation_receipt` JSON RPC method. /// /// # Arguments - /// * `uo_hash` - The [UserOperationHash](UserOperationHash) to get the user operation receipt for. + /// * `uo_hash` - The [UserOperationHash](UserOperationHash) to get the user operation receipt + /// for. /// /// # Returns /// `Result` - The user operation receipt, if any. @@ -631,7 +605,8 @@ where Err(format_err!("No user operation found")) } - /// Removes the [UserOperation](UserOperation) from the [UserOperationQueue](UserOperationQueue) given the [UserOperationHash](UserOperationHash). + /// Removes the [UserOperation](UserOperation) from the [UserOperationQueue](UserOperationQueue) + /// given the [UserOperationHash](UserOperationHash). /// /// # Arguments /// * `uo_hash` - The [UserOperationHash](UserOperationHash) to remove the user operation for. @@ -648,10 +623,13 @@ where None } - /// Removes multiple [UserOperations](UserOperation) from the [UserOperationQueue](UserOperationQueue) given an array of [UserOperationHash](UserOperationHash). + /// Removes multiple [UserOperations](UserOperation) from the + /// [UserOperationQueue](UserOperationQueue) given an array of + /// [UserOperationHash](UserOperationHash). /// /// # Arguments - /// * `uo_hashes` - The array of [UserOperationHash](UserOperationHash) to remove the user operations for. + /// * `uo_hashes` - The array of [UserOperationHash](UserOperationHash) to remove the user + /// operations for. /// /// # Returns /// `Option<()>` - None diff --git a/crates/uopool/src/utils.rs b/crates/mempool/src/utils.rs similarity index 86% rename from crates/uopool/src/utils.rs rename to crates/mempool/src/utils.rs index 756ac8f5..96dbcbe6 100644 --- a/crates/uopool/src/utils.rs +++ b/crates/mempool/src/utils.rs @@ -7,10 +7,8 @@ pub fn equal_code_hashes(hashes: &Vec, hashes_prev: &Vec) -> return false; } - let hashes_map = hashes - .iter() - .map(|h: &CodeHash| (h.address, h.hash)) - .collect::>(); + let hashes_map = + hashes.iter().map(|h: &CodeHash| (h.address, h.hash)).collect::>(); for hash_prev in hashes_prev { if let Some(hash) = hashes_map.get(&hash_prev.address) { @@ -53,7 +51,8 @@ impl Default for Overhead { impl Overhead { /// Calculates the pre-verification gas of a [UserOperation](UserOperation) - /// The function first packs the [UserOperation](UserOperation) by calling the [pack](UserOperation::pack) method, then extracts the call data for gas calculation. + /// The function first packs the [UserOperation](UserOperation) by calling the + /// [pack](UserOperation::pack) method, then extracts the call data for gas calculation. /// /// # Arguments /// `uo` - The [UserOperation](UserOperation) to calculate the pre-verification gas for @@ -64,11 +63,7 @@ impl Overhead { let uo_pack = uo.pack(); let call_data = uo_pack.deref().iter().fold(U256::zero(), |acc, &x| { - let byte_cost = if x == 0 { - &self.zero_byte - } else { - &self.non_zero_byte - }; + let byte_cost = if x == 0 { &self.zero_byte } else { &self.non_zero_byte }; acc.saturating_add(*byte_cost) }); @@ -76,8 +71,7 @@ impl Overhead { // -> (per_user_op_word * (uo_pack.len() + 31)) / 32 // -> (per_user_op_word * (uo_pack.len() + 31)) / 32 + rounding_const let word_cost = div_ceil( - self.per_user_op_word - .saturating_mul(U256::from(uo_pack.len() + 31)), + self.per_user_op_word.saturating_mul(U256::from(uo_pack.len() + 31)), U256::from(32), ); @@ -93,7 +87,8 @@ impl Overhead { } /// Helper function to calculate the valid gas of a [UserOperation](UserOperation) -/// The function is invoked by the [check_valid_gas](crates::uopool::validate::sanity::check_valid_gas) method. +/// The function is invoked by the +/// [check_valid_gas](crates::uopool::validate::sanity::check_valid_gas) method. /// /// # Arguments /// `gas_price` - The gas price @@ -112,7 +107,8 @@ pub fn calculate_valid_gas(gas_price: U256, gas_incr_perc: U256) -> U256 { } /// Helper function to calculate the call gas limit of a [UserOperation](UserOperation) -/// The function is invoked by the [estimate_user_operation_gas](crates::uopool::estimate::estimate_user_operation_gas) method. +/// The function is invoked by the +/// [estimate_user_operation_gas](crates::uopool::estimate::estimate_user_operation_gas) method. /// /// # Arguments /// `paid` - The paid gas @@ -124,9 +120,7 @@ pub fn calculate_valid_gas(gas_price: U256, gas_incr_perc: U256) -> U256 { pub fn calculate_call_gas_limit(paid: U256, pre_op_gas: U256, fee_per_gas: U256) -> U256 { // paid / fee_per_gas - pre_op_gas + Overhead::default().fixed // -> (paid / fee_per_gas + rounding_cost) - pre_op_gas + Overhead::default().fixed - div_ceil(paid, fee_per_gas) - .saturating_sub(pre_op_gas) - .saturating_add(Overhead::default().fixed) + div_ceil(paid, fee_per_gas).saturating_sub(pre_op_gas).saturating_add(Overhead::default().fixed) } /// Performs division and rounds up to the nearest integer. @@ -143,17 +137,13 @@ pub fn calculate_call_gas_limit(paid: U256, pre_op_gas: U256, fee_per_gas: U256) /// assert_eq!(result, U256::from(4)); /// ``` fn div_ceil(numerator: U256, denominator: U256) -> U256 { - let rounding_const = U256::from( - if numerator.checked_rem(denominator).unwrap_or_default() > U256::zero() { + let rounding_const = + U256::from(if numerator.checked_rem(denominator).unwrap_or_default() > U256::zero() { 1 } else { 0 - }, - ); - numerator - .checked_div(denominator) - .unwrap_or_default() - .saturating_add(rounding_const) + }); + numerator.checked_div(denominator).unwrap_or_default().saturating_add(rounding_const) } #[cfg(test)] @@ -194,9 +184,7 @@ pub mod tests { fn pre_verification_gas_calculation_with_large_user_operation() { let gas_oh = Overhead::default(); let uo = UserOperation { - sender: "0xAB7e2cbFcFb6A5F33A75aD745C3E5fB48d689B54" - .parse() - .unwrap(), + sender: "0xAB7e2cbFcFb6A5F33A75aD745C3E5fB48d689B54".parse().unwrap(), nonce: U256::max_value(), init_code: Bytes::from(vec![255; 1024]), // Large init_code call_data: Bytes::from(vec![255; 1024]), // Large call_data @@ -224,9 +212,7 @@ pub mod tests { sig_size: U256::from(65), }; let uo = UserOperation { - sender: "0xAB7e2cbFcFb6A5F33A75aD745C3E5fB48d689B54" - .parse() - .unwrap(), + sender: "0xAB7e2cbFcFb6A5F33A75aD745C3E5fB48d689B54".parse().unwrap(), nonce: U256::max_value(), init_code: Bytes::from(vec![255; 1024]), // Large init_code call_data: Bytes::from(vec![255; 1024]), // Large call_data @@ -270,8 +256,8 @@ pub mod tests { signature: Bytes::from(vec![255; 1024]), // Large signature }; - // This test is mainly to check if the function can handle the overflow scenario without panicking. - // We don't have a specific expected value in this case. + // This test is mainly to check if the function can handle the overflow scenario without + // panicking. We don't have a specific expected value in this case. let _ = gas_oh.calculate_pre_verification_gas(&uo); } @@ -295,10 +281,7 @@ pub mod tests { let paid = U256::from(100); let pre_op_gas = U256::from(10); let fee_per_gas = U256::from(1); - assert_eq!( - calculate_call_gas_limit(paid, pre_op_gas, fee_per_gas), - 21090.into() - ); + assert_eq!(calculate_call_gas_limit(paid, pre_op_gas, fee_per_gas), 21090.into()); } #[test] @@ -306,10 +289,7 @@ pub mod tests { let paid = U256::from(100); let pre_op_gas = U256::from(10); let fee_per_gas = U256::from(0); - assert_eq!( - calculate_call_gas_limit(paid, pre_op_gas, fee_per_gas), - 21000.into() - ); + assert_eq!(calculate_call_gas_limit(paid, pre_op_gas, fee_per_gas), 21000.into()); } #[test] @@ -410,13 +390,8 @@ pub mod tests { ..UserOperation::random() }; let uo_hash = mempool.add(uo.clone(), &ep, &chain_id).unwrap(); - let code_hashes = vec![CodeHash { - address: Address::random(), - hash: H256::random(), - }]; - mempool - .set_code_hashes(&uo_hash, code_hashes.clone()) - .unwrap(); + let code_hashes = vec![CodeHash { address: Address::random(), hash: H256::random() }]; + mempool.set_code_hashes(&uo_hash, code_hashes.clone()).unwrap(); assert!(mempool.has_code_hashes(&uo_hash).unwrap()); @@ -461,18 +436,9 @@ pub mod tests { assert_eq!(reputation.add_whitelist(&addrs[2]), true); assert_eq!(reputation.add_blacklist(&addrs[1]), true); - assert_eq!( - Status::from(reputation.get_status(&addrs[2]).unwrap()), - Status::OK - ); - assert_eq!( - Status::from(reputation.get_status(&addrs[1]).unwrap()), - Status::BANNED - ); - assert_eq!( - Status::from(reputation.get_status(&addrs[3]).unwrap()), - Status::OK - ); + assert_eq!(Status::from(reputation.get_status(&addrs[2]).unwrap()), Status::OK); + assert_eq!(Status::from(reputation.get_status(&addrs[1]).unwrap()), Status::BANNED); + assert_eq!(Status::from(reputation.get_status(&addrs[3]).unwrap()), Status::OK); assert_eq!(reputation.increment_seen(&addrs[2]).unwrap(), ()); assert_eq!(reputation.increment_seen(&addrs[2]).unwrap(), ()); @@ -483,25 +449,16 @@ pub mod tests { assert_eq!(reputation.increment_included(&addrs[2]).unwrap(), ()); assert_eq!(reputation.increment_included(&addrs[3]).unwrap(), ()); - assert_eq!( - reputation.update_handle_ops_reverted(&addrs[3]).unwrap(), - () - ); + assert_eq!(reputation.update_handle_ops_reverted(&addrs[3]).unwrap(), ()); for _ in 0..250 { assert_eq!(reputation.increment_seen(&addrs[3]).unwrap(), ()); } - assert_eq!( - Status::from(reputation.get_status(&addrs[3]).unwrap()), - Status::THROTTLED - ); + assert_eq!(Status::from(reputation.get_status(&addrs[3]).unwrap()), Status::THROTTLED); for _ in 0..500 { assert_eq!(reputation.increment_seen(&addrs[3]).unwrap(), ()); } - assert_eq!( - Status::from(reputation.get_status(&addrs[3]).unwrap()), - Status::BANNED - ); + assert_eq!(Status::from(reputation.get_status(&addrs[3]).unwrap()), Status::BANNED); } } diff --git a/crates/uopool/src/validate/mod.rs b/crates/mempool/src/validate/mod.rs similarity index 94% rename from crates/uopool/src/validate/mod.rs rename to crates/mempool/src/validate/mod.rs index 5bd29e8d..cabd76ca 100644 --- a/crates/uopool/src/validate/mod.rs +++ b/crates/mempool/src/validate/mod.rs @@ -9,11 +9,11 @@ use enumset::{EnumSet, EnumSetType}; use ethers::{providers::Middleware, types::U256}; use silius_contracts::{entry_point::SimulateValidationResult, tracer::JsTracerFrame, EntryPoint}; use silius_primitives::{ - consts::entities::NUMBER_LEVELS, + constants::validation::entities::NUMBER_OF_LEVELS, + mempool::ValidationError, reputation::StakeInfo, sanity::SanityCheckError, simulation::{CodeHash, SimulationCheckError, StorageMap}, - uopool::ValidationError, UserOperation, UserOperationHash, }; @@ -48,7 +48,8 @@ pub enum UserOperationValidatorMode { } /// The [UserOperation](UserOperation) validator trait. -/// The [UserOperationValidator](UserOperationValidator) is a composable trait that allows bundler to choose validation rules(sanity, simultation, simulation trace) to apply. +/// The [UserOperationValidator](UserOperationValidator) is a composable trait that allows bundler +/// to choose validation rules(sanity, simultation, simulation trace) to apply. #[async_trait::async_trait] pub trait UserOperationValidator: Send + Sync { async fn validate_user_operation( @@ -166,8 +167,8 @@ impl SanityCheck for () { } // These macro enable people to chain sanity check implementations.: -// `(SanityCheck1, SanityCheck2, SanityCheck3, ...).check_user_operation(uo, mempool, reputation, helper)`` -// SanityCheck1,2,3 could be any data type which implement SanityCheck trait. +// `(SanityCheck1, SanityCheck2, SanityCheck3, ...).check_user_operation(uo, mempool, reputation, +// helper)`` SanityCheck1,2,3 could be any data type which implement SanityCheck trait. sanity_check_impls! { A } sanity_check_impls! { A B } sanity_check_impls! { A B C } @@ -240,13 +241,14 @@ pub struct SimulationTraceHelper<'a, M: Middleware + Send + Sync + 'static> { chain: Chain, simulate_validation_result: &'a SimulateValidationResult, js_trace: &'a JsTracerFrame, - stake_info: Option<[StakeInfo; NUMBER_LEVELS]>, + stake_info: Option<[StakeInfo; NUMBER_OF_LEVELS]>, code_hashes: Option>, } #[async_trait::async_trait] pub trait SimulationTraceCheck: Send + Sync { - /// Asynchronously checks a user operation against the mempool, reputation, and simulation trace. + /// Asynchronously checks a user operation against the mempool, reputation, and simulation + /// trace. /// /// # Arguments /// @@ -266,7 +268,8 @@ pub trait SimulationTraceCheck: Send + Sync { /// /// # Returns /// - /// Returns `Ok(())` if the user operation passes the simulation check, or an error of type `SimulationCheckError` otherwise. + /// Returns `Ok(())` if the user operation passes the simulation check, or an error of type + /// `SimulationCheckError` otherwise. async fn check_user_operation( &self, uo: &UserOperation, @@ -332,8 +335,9 @@ impl SimulationTraceCheck for () { } // These macro enable people to chain simulation check implementations.: -// `(SimulationTraceCheck1, SimulationTraceCheck2, SimulationTraceCheck3, ...).check_user_operation(uo, mempool, reputeation helper)`` -// SimulationTraceCheck1,2,3 could be any data type which implement SimulationTraceCheck trait. +// `(SimulationTraceCheck1, SimulationTraceCheck2, SimulationTraceCheck3, +// ...).check_user_operation(uo, mempool, reputeation helper)`` SimulationTraceCheck1,2,3 could be +// any data type which implement SimulationTraceCheck trait. simulation_trace_check_impls! { A } simulation_trace_check_impls! { A B } simulation_trace_check_impls! { A B C } diff --git a/crates/uopool/src/validate/sanity/call_gas.rs b/crates/mempool/src/validate/sanity/call_gas.rs similarity index 100% rename from crates/uopool/src/validate/sanity/call_gas.rs rename to crates/mempool/src/validate/sanity/call_gas.rs diff --git a/crates/uopool/src/validate/sanity/entities.rs b/crates/mempool/src/validate/sanity/entities.rs similarity index 91% rename from crates/uopool/src/validate/sanity/entities.rs rename to crates/mempool/src/validate/sanity/entities.rs index 6bfc4b17..bbcaf8a0 100644 --- a/crates/uopool/src/validate/sanity/entities.rs +++ b/crates/mempool/src/validate/sanity/entities.rs @@ -5,7 +5,7 @@ use crate::{ }; use ethers::{providers::Middleware, types::Address}; use silius_primitives::{ - consts::{ + constants::validation::{ entities::{FACTORY, PAYMASTER, SENDER}, reputation::THROTTLED_ENTITY_MEMPOOL_COUNT, }, @@ -54,7 +54,8 @@ impl Entities { Ok(()) } - /// [SREP-030] - THROTTLED address is limited to THROTTLED_ENTITY_MEMPOOL_COUNT entries in the mempool + /// [SREP-030] - THROTTLED address is limited to THROTTLED_ENTITY_MEMPOOL_COUNT entries in the + /// mempool fn check_throttled( &self, entity: &str, @@ -72,9 +73,9 @@ impl Entities { H: HashSetOp, R: ReputationEntryOp, { - if *status == Status::THROTTLED - && (mempool.get_number_by_sender(addr) + mempool.get_number_by_entity(addr)) - >= THROTTLED_ENTITY_MEMPOOL_COUNT + if *status == Status::THROTTLED && + (mempool.get_number_by_sender(addr) + mempool.get_number_by_entity(addr)) >= + THROTTLED_ENTITY_MEMPOOL_COUNT { return Err(ReputationError::ThrottledLimit { entity: entity.to_string(), @@ -89,11 +90,13 @@ impl Entities { #[async_trait::async_trait] impl SanityCheck for Entities { - /// The [check_user_operation] method implementation that performs the sanity check for the staked entities. + /// The [check_user_operation] method implementation that performs the sanity check for the + /// staked entities. /// /// # Arguments /// `uo` - The user operation to be checked. - /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to perform the sanity check. + /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to + /// perform the sanity check. /// /// # Returns /// None if the sanity check is successful, otherwise a [SanityCheckError] is returned. diff --git a/crates/uopool/src/validate/sanity/max_fee.rs b/crates/mempool/src/validate/sanity/max_fee.rs similarity index 86% rename from crates/uopool/src/validate/sanity/max_fee.rs rename to crates/mempool/src/validate/sanity/max_fee.rs index b820d6d8..8766c972 100644 --- a/crates/uopool/src/validate/sanity/max_fee.rs +++ b/crates/mempool/src/validate/sanity/max_fee.rs @@ -52,17 +52,11 @@ impl SanityCheck for MaxFee { .eth_client() .get_block(BlockNumber::Latest) .await - .map_err(|err| SanityCheckError::UnknownError { - message: err.to_string(), - })? - .ok_or(SanityCheckError::UnknownError { - message: "No block found".to_string(), - })?; + .map_err(|err| SanityCheckError::UnknownError { message: err.to_string() })? + .ok_or(SanityCheckError::UnknownError { message: "No block found".to_string() })?; let base_fee_per_gas = block .base_fee_per_gas - .ok_or(SanityCheckError::UnknownError { - message: "No base fee".to_string(), - })?; + .ok_or(SanityCheckError::UnknownError { message: "No base fee".to_string() })?; if base_fee_per_gas > uo.max_fee_per_gas { return Err(SanityCheckError::LowMaxFeePerGas { diff --git a/crates/uopool/src/validate/sanity/mod.rs b/crates/mempool/src/validate/sanity/mod.rs similarity index 67% rename from crates/uopool/src/validate/sanity/mod.rs rename to crates/mempool/src/validate/sanity/mod.rs index 14b3e064..a83a2f42 100644 --- a/crates/uopool/src/validate/sanity/mod.rs +++ b/crates/mempool/src/validate/sanity/mod.rs @@ -1,4 +1,5 @@ -//! Sanity module performs call gas limit, verification gas limit, max priority fee, paymaster verification, sender vericiation, and UserOperation type checks +//! Sanity module performs call gas limit, verification gas limit, max priority fee, paymaster +//! verification, sender vericiation, and UserOperation type checks pub mod call_gas; pub mod entities; pub mod max_fee; diff --git a/crates/uopool/src/validate/sanity/paymaster.rs b/crates/mempool/src/validate/sanity/paymaster.rs similarity index 84% rename from crates/uopool/src/validate/sanity/paymaster.rs rename to crates/mempool/src/validate/sanity/paymaster.rs index 6891018a..a90bc29f 100644 --- a/crates/uopool/src/validate/sanity/paymaster.rs +++ b/crates/mempool/src/validate/sanity/paymaster.rs @@ -12,11 +12,13 @@ pub struct Paymaster; #[async_trait::async_trait] impl SanityCheck for Paymaster { - /// The [check_user_operation] method implementation that performs the sanity check on the paymaster. + /// The [check_user_operation] method implementation that performs the sanity check on the + /// paymaster. /// /// # Arguments /// `uo` - The user operation to be checked. - /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to perform the sanity check. + /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to + /// perform the sanity check. /// /// # Returns /// None if the sanity check is successful, otherwise a [SanityCheckError] is returned. @@ -41,13 +43,11 @@ impl SanityCheck for Paymaster { if !code.is_empty() { let deposit_info = - helper - .entry_point - .get_deposit_info(&addr) - .await - .map_err(|_| SanityCheckError::UnknownError { + helper.entry_point.get_deposit_info(&addr).await.map_err(|_| { + SanityCheckError::UnknownError { message: "Couldn't retrieve deposit info from entry point".into(), - })?; + } + })?; if U256::from(deposit_info.deposit) >= uo.max_fee_per_gas { return Ok(()); diff --git a/crates/uopool/src/validate/sanity/sender.rs b/crates/mempool/src/validate/sanity/sender.rs similarity index 74% rename from crates/uopool/src/validate/sanity/sender.rs rename to crates/mempool/src/validate/sanity/sender.rs index ed0df9c3..c1f150c0 100644 --- a/crates/uopool/src/validate/sanity/sender.rs +++ b/crates/mempool/src/validate/sanity/sender.rs @@ -7,7 +7,7 @@ use crate::{ }; use ethers::providers::Middleware; use silius_primitives::{ - consts::uopool::GAS_INCREASE_PERC, sanity::SanityCheckError, UserOperation, + constants::mempool::GAS_INCREASE_PERC, sanity::SanityCheckError, UserOperation, }; #[derive(Clone)] @@ -15,14 +15,17 @@ pub struct Sender; #[async_trait::async_trait] impl SanityCheck for Sender { - /// The [check_user_operation] method implementation that performs the check for the sender of the [UserOperation](UserOperation). + /// The [check_user_operation] method implementation that performs the check for the sender of + /// the [UserOperation](UserOperation). /// /// # Arguments /// `uo` - The [UserOperation](UserOperation) to be checked. - /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to perform the sanity check. + /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to + /// perform the sanity check. /// /// # Returns - /// Nothing if the sanity check is successful, otherwise a [SanityCheckError](SanityCheckError) is returned. + /// Nothing if the sanity check is successful, otherwise a [SanityCheckError](SanityCheckError) + /// is returned. async fn check_user_operation( &self, uo: &UserOperation, @@ -38,15 +41,11 @@ impl SanityCheck for Sender { H: HashSetOp, R: ReputationEntryOp, { - let code = helper - .entry_point - .eth_client() - .get_code(uo.sender, None) - .await?; + let code = helper.entry_point.eth_client().get_code(uo.sender, None).await?; // check if sender or init code - if (code.is_empty() && uo.init_code.is_empty()) - || (!code.is_empty() && !uo.init_code.is_empty()) + if (code.is_empty() && uo.init_code.is_empty()) || + (!code.is_empty() && !uo.init_code.is_empty()) { return Err(SanityCheckError::SenderOrInitCode { sender: uo.sender, @@ -66,10 +65,10 @@ impl SanityCheck for Sender { .cloned(); if let Some(uo_prev) = uo_prev { - if uo.max_fee_per_gas - < calculate_valid_gas(uo_prev.max_fee_per_gas, GAS_INCREASE_PERC.into()) - || uo.max_priority_fee_per_gas - < calculate_valid_gas( + if uo.max_fee_per_gas < + calculate_valid_gas(uo_prev.max_fee_per_gas, GAS_INCREASE_PERC.into()) || + uo.max_priority_fee_per_gas < + calculate_valid_gas( uo_prev.max_priority_fee_per_gas, GAS_INCREASE_PERC.into(), ) diff --git a/crates/uopool/src/validate/sanity/unstaked_entities.rs b/crates/mempool/src/validate/sanity/unstaked_entities.rs similarity index 80% rename from crates/uopool/src/validate/sanity/unstaked_entities.rs rename to crates/mempool/src/validate/sanity/unstaked_entities.rs index 650853fe..dc8552bf 100644 --- a/crates/uopool/src/validate/sanity/unstaked_entities.rs +++ b/crates/mempool/src/validate/sanity/unstaked_entities.rs @@ -8,7 +8,7 @@ use ethers::{ types::{Address, U256}, }; use silius_primitives::{ - consts::{ + constants::validation::{ entities::{FACTORY, PAYMASTER, SENDER}, reputation::{ INCLUSION_RATE_FACTOR, SAME_SENDER_MEMPOOL_COUNT, SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT, @@ -30,13 +30,11 @@ impl UnstakedEntities { addr: &Address, helper: &SanityHelper<'a, M>, ) -> Result { - let info = helper - .entry_point - .get_deposit_info(addr) - .await - .map_err(|_| SanityCheckError::UnknownError { + let info = helper.entry_point.get_deposit_info(addr).await.map_err(|_| { + SanityCheckError::UnknownError { message: "Couldn't retrieve deposit info from entry point".to_string(), - })?; + } + })?; Ok(StakeInfo { address: *addr, @@ -56,11 +54,9 @@ impl UnstakedEntities { H: HashSetOp, R: ReputationEntryOp, { - reputation - .get(addr) - .map_err(|_| SanityCheckError::UnknownError { - message: "Failed to retrieve reputation entry".into(), - }) + reputation.get(addr).map_err(|_| SanityCheckError::UnknownError { + message: "Failed to retrieve reputation entry".into(), + }) } /// Calculates allowed number of user operations @@ -68,21 +64,23 @@ impl UnstakedEntities { if entity.uo_seen == 0 { SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT as u64 } else { - SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT as u64 - + ((entity.uo_included as f64 / entity.uo_seen as f64) - * INCLUSION_RATE_FACTOR as f64) as u64 - + cmp::min(entity.uo_included, 10000) + SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT as u64 + + ((entity.uo_included as f64 / entity.uo_seen as f64) * INCLUSION_RATE_FACTOR as f64) + as u64 + + cmp::min(entity.uo_included, 10000) } } } #[async_trait::async_trait] impl SanityCheck for UnstakedEntities { - /// The [check_user_operation] method implementation that performs the sanity check for the unstaked entities. + /// The [check_user_operation] method implementation that performs the sanity check for the + /// unstaked entities. /// /// # Arguments /// `uo` - The user operation to be checked. - /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to perform the sanity check. + /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to + /// perform the sanity check. /// /// # Returns /// None if the sanity check is successful, otherwise a [SanityCheckError] is returned. @@ -103,10 +101,12 @@ impl SanityCheck for UnstakedEntities { { let (sender, factory, paymaster) = uo.get_entities(); - // [SREP-010] - the "canonical mempool" defines a staked entity if it has MIN_STAKE_VALUE and unstake delay of MIN_UNSTAKE_DELAY + // [SREP-010] - the "canonical mempool" defines a staked entity if it has MIN_STAKE_VALUE + // and unstake delay of MIN_UNSTAKE_DELAY // sender - // [STO-040] - UserOperation may not use an entity address (factory/paymaster/aggregator) that is used as an "account" in another UserOperation in the mempool + // [STO-040] - UserOperation may not use an entity address (factory/paymaster/aggregator) + // that is used as an "account" in another UserOperation in the mempool if mempool.get_number_by_entity(&sender) > 0 { return Err(SanityCheckError::EntityVerification { entity: SENDER.to_string(), @@ -117,10 +117,11 @@ impl SanityCheck for UnstakedEntities { }); } - // [UREP-010] - UserOperation with unstaked sender are only allowed up to SAME_SENDER_MEMPOOL_COUNT times in the mempool + // [UREP-010] - UserOperation with unstaked sender are only allowed up to + // SAME_SENDER_MEMPOOL_COUNT times in the mempool let sender_stake = self.get_stake(&sender, helper).await?; - if reputation.verify_stake(SENDER, Some(sender_stake)).is_err() - && mempool.get_number_by_sender(&uo.sender) >= SAME_SENDER_MEMPOOL_COUNT + if reputation.verify_stake(SENDER, Some(sender_stake)).is_err() && + mempool.get_number_by_sender(&uo.sender) >= SAME_SENDER_MEMPOOL_COUNT { return Err(ReputationError::UnstakedEntityVerification { entity: SENDER.to_string(), @@ -132,7 +133,9 @@ impl SanityCheck for UnstakedEntities { // factory if let Some(factory) = factory { - // [STO-040] - UserOperation may not use an entity address (factory/paymaster/aggregator) that is used as an "account" in another UserOperation in the mempool + // [STO-040] - UserOperation may not use an entity address + // (factory/paymaster/aggregator) that is used as an "account" in another UserOperation + // in the mempool if mempool.get_number_by_sender(&factory) > 0 { return Err(SanityCheckError::EntityVerification { entity: FACTORY.to_string(), @@ -144,10 +147,7 @@ impl SanityCheck for UnstakedEntities { } let factory_stake = self.get_stake(&factory, helper).await?; - if reputation - .verify_stake(FACTORY, Some(factory_stake)) - .is_err() - { + if reputation.verify_stake(FACTORY, Some(factory_stake)).is_err() { // [UREP-020] - for other entities let entity = self.get_entity(&factory, helper, reputation)?; let uos_allowed = Self::calculate_allowed_user_operations(entity); @@ -164,7 +164,9 @@ impl SanityCheck for UnstakedEntities { // paymaster if let Some(paymaster) = paymaster { - // [STO-040] - UserOperation may not use an entity address (factory/paymaster/aggregator) that is used as an "account" in another UserOperation in the mempool + // [STO-040] - UserOperation may not use an entity address + // (factory/paymaster/aggregator) that is used as an "account" in another UserOperation + // in the mempool if mempool.get_number_by_sender(&paymaster) > 0 { return Err(SanityCheckError::EntityVerification { entity: PAYMASTER.to_string(), @@ -176,10 +178,7 @@ impl SanityCheck for UnstakedEntities { } let paymaster_stake = self.get_stake(&paymaster, helper).await?; - if reputation - .verify_stake(PAYMASTER, Some(paymaster_stake)) - .is_err() - { + if reputation.verify_stake(PAYMASTER, Some(paymaster_stake)).is_err() { // [UREP-020] - for other entities let entity = self.get_entity(&paymaster, helper, reputation)?; let uos_allowed = Self::calculate_allowed_user_operations(entity); diff --git a/crates/uopool/src/validate/sanity/verification_gas.rs b/crates/mempool/src/validate/sanity/verification_gas.rs similarity index 91% rename from crates/uopool/src/validate/sanity/verification_gas.rs rename to crates/mempool/src/validate/sanity/verification_gas.rs index 802ef95b..8f2e90e9 100644 --- a/crates/uopool/src/validate/sanity/verification_gas.rs +++ b/crates/mempool/src/validate/sanity/verification_gas.rs @@ -14,14 +14,17 @@ pub struct VerificationGas { #[async_trait::async_trait] impl SanityCheck for VerificationGas { - /// The [check_user_operation] method implementation that performs the check on verification gas. + /// The [check_user_operation] method implementation that performs the check on verification + /// gas. /// /// # Arguments /// `uo` - The [UserOperation](UserOperation) to be checked. - /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to perform the sanity check. + /// `helper` - The [sanity check helper](SanityHelper) that contains the necessary data to + /// perform the sanity check. /// /// # Returns - /// Nothing if the sanity check is successful, otherwise a [SanityCheckError](SanityCheckError) is returned. + /// Nothing if the sanity check is successful, otherwise a [SanityCheckError](SanityCheckError) + /// is returned. async fn check_user_operation( &self, uo: &UserOperation, diff --git a/crates/uopool/src/validate/simulation/mod.rs b/crates/mempool/src/validate/simulation/mod.rs similarity index 100% rename from crates/uopool/src/validate/simulation/mod.rs rename to crates/mempool/src/validate/simulation/mod.rs diff --git a/crates/uopool/src/validate/simulation/signature.rs b/crates/mempool/src/validate/simulation/signature.rs similarity index 95% rename from crates/uopool/src/validate/simulation/signature.rs rename to crates/mempool/src/validate/simulation/signature.rs index 02450980..9ab35998 100644 --- a/crates/uopool/src/validate/simulation/signature.rs +++ b/crates/mempool/src/validate/simulation/signature.rs @@ -6,7 +6,8 @@ use silius_primitives::{simulation::SimulationCheckError, UserOperation}; pub struct Signature; impl SimulationCheck for Signature { - /// The [check_user_operation] method implementation that validates the signature of the user operation. + /// The [check_user_operation] method implementation that validates the signature of the user + /// operation. /// /// # Arguments /// `_uo` - Not used in this check diff --git a/crates/uopool/src/validate/simulation/timestamp.rs b/crates/mempool/src/validate/simulation/timestamp.rs similarity index 87% rename from crates/uopool/src/validate/simulation/timestamp.rs rename to crates/mempool/src/validate/simulation/timestamp.rs index 7129f418..b745521b 100644 --- a/crates/uopool/src/validate/simulation/timestamp.rs +++ b/crates/mempool/src/validate/simulation/timestamp.rs @@ -10,7 +10,8 @@ use std::time::{SystemTime, UNIX_EPOCH}; pub struct Timestamp; impl SimulationCheck for Timestamp { - /// The [check_user_operation] method implementation that checks the timestamp of the [UserOperation](UserOperation). + /// The [check_user_operation] method implementation that checks the timestamp of the + /// [UserOperation](UserOperation). /// /// # Arguments /// `_uo` - Not used in this check @@ -38,7 +39,8 @@ impl SimulationCheck for Timestamp { return Err(SimulationCheckError::Expiration { valid_after, valid_until, - paymaster: None, // TODO: fill with paymaster address this error was triggered by the paymaster + paymaster: None, /* TODO: fill with paymaster address this error was triggered by + * the paymaster */ }); } diff --git a/crates/uopool/src/validate/simulation_trace/call_stack.rs b/crates/mempool/src/validate/simulation_trace/call_stack.rs similarity index 87% rename from crates/uopool/src/validate/simulation_trace/call_stack.rs rename to crates/mempool/src/validate/simulation_trace/call_stack.rs index ae7d5dad..08d7f9c0 100644 --- a/crates/uopool/src/validate/simulation_trace/call_stack.rs +++ b/crates/mempool/src/validate/simulation_trace/call_stack.rs @@ -10,7 +10,7 @@ use silius_contracts::{ tracer::{Call, CallEntry, JsTracerFrame}, }; use silius_primitives::{ - consts::entities::{LEVEL_TO_ENTITY, PAYMASTER}, + constants::validation::entities::{LEVEL_TO_ENTITY, PAYMASTER}, simulation::{ SimulationCheckError, CREATE_OPCODE, RETURN_OPCODE, REVERT_OPCODE, VALIDATE_PAYMASTER_USER_OP_FUNCTION, @@ -126,12 +126,13 @@ impl SimulationTraceCheck for CallStack { self.parse_call_stack(helper.js_trace, &mut calls)?; for call in calls.iter() { - // [OP-052] - may call depositTo(sender) with any value from either the sender or factory - // [OP-053] - may call the fallback function from the sender with any value - if call.to.unwrap_or_default() == helper.entry_point.address() - && call.from.unwrap_or_default() != helper.entry_point.address() - && (call.method.is_some() - && call.method.clone().unwrap_or_default() != *"depositTo") + // [OP-052] - may call depositTo(sender) with any value from either the sender or + // factory [OP-053] - may call the fallback function from the sender with + // any value + if call.to.unwrap_or_default() == helper.entry_point.address() && + call.from.unwrap_or_default() != helper.entry_point.address() && + (call.method.is_some() && + call.method.clone().unwrap_or_default() != *"depositTo") { // [OP-054] - any other access to the EntryPoint is forbidden return Err(SimulationCheckError::CallStack { @@ -139,9 +140,10 @@ impl SimulationTraceCheck for CallStack { }); } - // [OP-061] - CALL with value is forbidden. The only exception is a call to the EntryPoint described above - if call.to.unwrap_or_default() != helper.entry_point.address() - && !call.value.unwrap_or_default().is_zero() + // [OP-061] - CALL with value is forbidden. The only exception is a call to the + // EntryPoint described above + if call.to.unwrap_or_default() != helper.entry_point.address() && + !call.value.unwrap_or_default().is_zero() { return Err(SimulationCheckError::CallStack { message: format!("Illegal call {call:?}"), @@ -150,9 +152,9 @@ impl SimulationTraceCheck for CallStack { // paymaster for (i, stake_info) in helper.stake_info.unwrap_or_default().iter().enumerate() { - if LEVEL_TO_ENTITY[i] == PAYMASTER - && call.method == Some(VALIDATE_PAYMASTER_USER_OP_FUNCTION.clone()) - && call.to == Some(stake_info.address) + if LEVEL_TO_ENTITY[i] == PAYMASTER && + call.method == Some(VALIDATE_PAYMASTER_USER_OP_FUNCTION.clone()) && + call.to == Some(stake_info.address) { if let Some(ret) = call.ret.as_ref() { let validate_paymaster_return: ValidatePaymasterUserOpReturn = @@ -166,10 +168,8 @@ impl SimulationTraceCheck for CallStack { // [EREP-050] - an unstaked paymaster may not return a context // This will be removed in the future - if !context.is_empty() - && reputation - .verify_stake(PAYMASTER, Some(*stake_info)) - .is_err() + if !context.is_empty() && + reputation.verify_stake(PAYMASTER, Some(*stake_info)).is_err() { return Err(SimulationCheckError::Unstaked { entity: PAYMASTER.to_string(), diff --git a/crates/uopool/src/validate/simulation_trace/code_hashes.rs b/crates/mempool/src/validate/simulation_trace/code_hashes.rs similarity index 88% rename from crates/uopool/src/validate/simulation_trace/code_hashes.rs rename to crates/mempool/src/validate/simulation_trace/code_hashes.rs index 0350afc6..82900bcb 100644 --- a/crates/uopool/src/validate/simulation_trace/code_hashes.rs +++ b/crates/mempool/src/validate/simulation_trace/code_hashes.rs @@ -52,10 +52,7 @@ impl CodeHashes { while let Some(res) = ts.join_next().await { match res { - Ok(Some(h)) => hashes.push(CodeHash { - address: h.0, - hash: h.1, - }), + Ok(Some(h)) => hashes.push(CodeHash { address: h.0, hash: h.1 }), Ok(None) | Err(_) => { return Err(SimulationCheckError::UnknownError { message: "Failed to retrieve code hashes".to_string(), @@ -93,7 +90,8 @@ impl SimulationTraceCheck for CodeHashes { H: HashSetOp, R: ReputationEntryOp, { - // [COD-010] - between the first and the second validations, the EXTCODEHASH value of any visited address, entity or referenced library, may not be changed + // [COD-010] - between the first and the second validations, the EXTCODEHASH value of any + // visited address, entity or referenced library, may not be changed let addrs = helper .js_trace @@ -103,8 +101,7 @@ impl SimulationTraceCheck for CodeHashes { .collect::>(); let hashes: &mut Vec = &mut vec![]; - self.get_code_hashes(addrs, hashes, &helper.entry_point.eth_client()) - .await?; + self.get_code_hashes(addrs, hashes, &helper.entry_point.eth_client()).await?; let uo_hash = uo.hash(&helper.entry_point.address(), &helper.chain.id().into()); @@ -112,9 +109,7 @@ impl SimulationTraceCheck for CodeHashes { Ok(true) => { // 2nd simulation let hashes_prev = mempool.get_code_hashes(&uo_hash).map_err(|err| { - SimulationCheckError::UnknownError { - message: format!("{err:?}"), - } + SimulationCheckError::UnknownError { message: format!("{err:?}") } })?; debug!( "Veryfing {:?} code hashes in 2nd simulation: {:?} vs {:?}", @@ -134,9 +129,7 @@ impl SimulationTraceCheck for CodeHashes { helper.code_hashes = Some(hashes.to_vec()); } Err(err) => { - return Err(SimulationCheckError::UnknownError { - message: format!("{err:?}"), - }) + return Err(SimulationCheckError::UnknownError { message: format!("{err:?}") }) } } diff --git a/crates/uopool/src/validate/simulation_trace/external_contracts.rs b/crates/mempool/src/validate/simulation_trace/external_contracts.rs similarity index 90% rename from crates/uopool/src/validate/simulation_trace/external_contracts.rs rename to crates/mempool/src/validate/simulation_trace/external_contracts.rs index cf3cc18c..d95127ce 100644 --- a/crates/uopool/src/validate/simulation_trace/external_contracts.rs +++ b/crates/mempool/src/validate/simulation_trace/external_contracts.rs @@ -7,7 +7,7 @@ use crate::{ use ethers::providers::Middleware; use silius_contracts::entry_point::SELECTORS_INDICES; use silius_primitives::{ - consts::entities::LEVEL_TO_ENTITY, + constants::validation::entities::LEVEL_TO_ENTITY, simulation::{SimulationCheckError, CREATE2_OPCODE}, UserOperation, }; @@ -33,12 +33,11 @@ impl SimulationTraceCheck for ExternalContracts { R: ReputationEntryOp, { for call_info in helper.js_trace.calls_from_entry_point.iter() { - let level = SELECTORS_INDICES - .get(call_info.top_level_method_sig.as_ref()) - .cloned(); + let level = SELECTORS_INDICES.get(call_info.top_level_method_sig.as_ref()).cloned(); if let Some(l) = level { - // [OP-041] - access to an address without a deployed code is forbidden for EXTCODE* and *CALL opcodes + // [OP-041] - access to an address without a deployed code is forbidden for EXTCODE* + // and *CALL opcodes for (addr, size) in call_info.contract_size.iter() { if *addr != uo.sender // [OP-042] - exception: access to "sender" address is allowed && size.contract_size <= 2 diff --git a/crates/uopool/src/validate/simulation_trace/gas.rs b/crates/mempool/src/validate/simulation_trace/gas.rs similarity index 92% rename from crates/uopool/src/validate/simulation_trace/gas.rs rename to crates/mempool/src/validate/simulation_trace/gas.rs index ab823328..5f3eb2c9 100644 --- a/crates/uopool/src/validate/simulation_trace/gas.rs +++ b/crates/mempool/src/validate/simulation_trace/gas.rs @@ -12,7 +12,8 @@ pub struct Gas; #[async_trait::async_trait] impl SimulationTraceCheck for Gas { - /// The [check_user_operation] method implementation that checks if the user operation runs out of gas + /// The [check_user_operation] method implementation that checks if the user operation runs out + /// of gas /// /// # Arguments /// `uo` - The user operation to check @@ -35,7 +36,8 @@ impl SimulationTraceCheck for Gas { H: HashSetOp, R: ReputationEntryOp, { - // [OP-020] - revert on "out of gas" is forbidden as it can "leak" the gas limit or the current call stack depth + // [OP-020] - revert on "out of gas" is forbidden as it can "leak" the gas limit or the + // current call stack depth for call_info in helper.js_trace.calls_from_entry_point.iter() { if call_info.oog.unwrap_or(false) { return Err(SimulationCheckError::OutOfGas {}); diff --git a/crates/uopool/src/validate/simulation_trace/mod.rs b/crates/mempool/src/validate/simulation_trace/mod.rs similarity index 100% rename from crates/uopool/src/validate/simulation_trace/mod.rs rename to crates/mempool/src/validate/simulation_trace/mod.rs diff --git a/crates/uopool/src/validate/simulation_trace/opcodes.rs b/crates/mempool/src/validate/simulation_trace/opcodes.rs similarity index 90% rename from crates/uopool/src/validate/simulation_trace/opcodes.rs rename to crates/mempool/src/validate/simulation_trace/opcodes.rs index e85be15f..4c6456ea 100644 --- a/crates/uopool/src/validate/simulation_trace/opcodes.rs +++ b/crates/mempool/src/validate/simulation_trace/opcodes.rs @@ -7,7 +7,7 @@ use crate::{ use ethers::providers::Middleware; use silius_contracts::entry_point::SELECTORS_INDICES; use silius_primitives::{ - consts::entities::{FACTORY, LEVEL_TO_ENTITY}, + constants::validation::entities::{FACTORY, LEVEL_TO_ENTITY}, simulation::{SimulationCheckError, CREATE2_OPCODE, FORBIDDEN_OPCODES}, UserOperation, }; @@ -41,9 +41,7 @@ impl SimulationTraceCheck for Opcodes { R: ReputationEntryOp, { for call_info in helper.js_trace.calls_from_entry_point.iter() { - let level = SELECTORS_INDICES - .get(call_info.top_level_method_sig.as_ref()) - .cloned(); + let level = SELECTORS_INDICES.get(call_info.top_level_method_sig.as_ref()).cloned(); if let Some(l) = level { // [OP-011] - block opcodes @@ -56,7 +54,8 @@ impl SimulationTraceCheck for Opcodes { } } - // [OP-031] - CREATE2 is allowed exactly once in the deployment phase and must deploy code for the "sender" address + // [OP-031] - CREATE2 is allowed exactly once in the deployment phase and must + // deploy code for the "sender" address if let Some(c) = call_info.opcodes.get(&*CREATE2_OPCODE) { if LEVEL_TO_ENTITY[l] == FACTORY && *c == 1 { continue; diff --git a/crates/uopool/src/validate/simulation_trace/storage_access.rs b/crates/mempool/src/validate/simulation_trace/storage_access.rs similarity index 87% rename from crates/uopool/src/validate/simulation_trace/storage_access.rs rename to crates/mempool/src/validate/simulation_trace/storage_access.rs index e2e55c1a..3c1a3b7e 100644 --- a/crates/uopool/src/validate/simulation_trace/storage_access.rs +++ b/crates/mempool/src/validate/simulation_trace/storage_access.rs @@ -11,7 +11,7 @@ use ethers::{ }; use silius_contracts::entry_point::SELECTORS_INDICES; use silius_primitives::{ - consts::entities::{FACTORY_LEVEL, LEVEL_TO_ENTITY, NUMBER_LEVELS}, + constants::validation::entities::{FACTORY_LEVEL, LEVEL_TO_ENTITY, NUMBER_OF_LEVELS}, reputation::StakeInfo, simulation::SimulationCheckError, UserOperation, @@ -34,7 +34,7 @@ impl StorageAccess { fn parse_slots( &self, keccak: Vec, - info: &[StakeInfo; NUMBER_LEVELS], + info: &[StakeInfo; NUMBER_OF_LEVELS], slots: &mut HashMap>, ) { for kecc in keccak { @@ -96,7 +96,8 @@ impl StorageAccess { #[async_trait::async_trait] impl SimulationTraceCheck for StorageAccess { - /// The [check_user_operation] method implementation that checks if the user operation access storage other than the one associated with itself. + /// The [check_user_operation] method implementation that checks if the user operation access + /// storage other than the one associated with itself. /// /// # Arguments /// `uo` - The [UserOperation](UserOperation) to check @@ -134,9 +135,7 @@ impl SimulationTraceCheck for StorageAccess { let stake_info = helper.stake_info.unwrap_or_default(); for call_info in helper.js_trace.calls_from_entry_point.iter() { - let level = SELECTORS_INDICES - .get(call_info.top_level_method_sig.as_ref()) - .cloned(); + let level = SELECTORS_INDICES.get(call_info.top_level_method_sig.as_ref()).cloned(); if let Some(l) = level { let stake_info_l = stake_info[l]; @@ -156,17 +155,21 @@ impl SimulationTraceCheck for StorageAccess { .concat() { if self.associated_with_slot(&uo.sender, &slot, &slots)? { - // [STO-021], [STO-022] - Access to associated storage of the account in an external (non-entity contract) is allowed if either The account already exists or There is an initCode and the factory contract is staked - if !(uo.init_code.is_empty() - || uo.sender == stake_info_l.address - && stake_info[FACTORY_LEVEL].is_staked()) + // [STO-021], [STO-022] - Access to associated storage of the account in + // an external (non-entity contract) is allowed if either The account + // already exists or There is an initCode and the factory contract is + // staked + if !(uo.init_code.is_empty() || + uo.sender == stake_info_l.address && + stake_info[FACTORY_LEVEL].is_staked()) { slot_staked = slot.clone(); } } else if *addr == stake_info_l.address // [STO-031] - access the entity's own storage (if entity staked) || self.associated_with_slot(&stake_info_l.address, &slot, &slots)? // [STO-032] - read/write Access to storage slots that is associated with the entity, in any non-entity contract (if entity staked) || !acc.writes.contains_key(&slot) - // [STO-033] - read-only access to any storage in non-entity contract (if entity staked) + // [STO-033] - read-only access to any storage in non-entity contract (if + // entity staked) { slot_staked = slot.clone(); } else { diff --git a/crates/uopool/src/validate/utils.rs b/crates/mempool/src/validate/utils.rs similarity index 92% rename from crates/uopool/src/validate/utils.rs rename to crates/mempool/src/validate/utils.rs index 11f82e3d..2ba20c36 100644 --- a/crates/uopool/src/validate/utils.rs +++ b/crates/mempool/src/validate/utils.rs @@ -1,8 +1,8 @@ use ethers::types::{Address, U256}; use silius_contracts::{entry_point::SimulateValidationResult, tracer::JsTracerFrame}; use silius_primitives::{ - consts::entities::NUMBER_LEVELS, get_address, reputation::StakeInfo, simulation::StorageMap, - UserOperation, + constants::validation::entities::NUMBER_OF_LEVELS, get_address, reputation::StakeInfo, + simulation::StorageMap, UserOperation, }; /// Helper function to extract the gas limit for verification from the simulation result @@ -62,7 +62,7 @@ pub fn extract_timestamps(sim_res: &SimulateValidationResult) -> (U256, U256) { pub fn extract_stake_info( uo: &UserOperation, sim_res: &SimulateValidationResult, -) -> [StakeInfo; NUMBER_LEVELS] { +) -> [StakeInfo; NUMBER_OF_LEVELS] { let (f_info, s_info, p_info) = match sim_res { SimulateValidationResult::ValidationResult(res) => { (res.factory_info, res.sender_info, res.paymaster_info) @@ -80,11 +80,7 @@ pub fn extract_stake_info( unstake_delay: f_info.1, }, // account - StakeInfo { - address: uo.sender, - stake: s_info.0, - unstake_delay: s_info.1, - }, + StakeInfo { address: uo.sender, stake: s_info.0, unstake_delay: s_info.1 }, // paymaster StakeInfo { address: get_address(&uo.paymaster_and_data).unwrap_or(Address::zero()), diff --git a/crates/uopool/src/validate/validator.rs b/crates/mempool/src/validate/validator.rs similarity index 76% rename from crates/uopool/src/validate/validator.rs rename to crates/mempool/src/validate/validator.rs index 95a84391..191c5297 100644 --- a/crates/uopool/src/validate/validator.rs +++ b/crates/mempool/src/validate/validator.rs @@ -30,44 +30,21 @@ use silius_contracts::{ EntryPoint, }; use silius_primitives::{ - sanity::SanityCheckError, simulation::SimulationCheckError, uopool::ValidationError, + mempool::ValidationError, sanity::SanityCheckError, simulation::SimulationCheckError, UserOperation, }; use tracing::debug; pub type StandardValidator = StandardUserOperationValidator< M, - ( - Sender, - VerificationGas, - CallGas, - MaxFee, - Paymaster, - Entities, - UnstakedEntities, - ), + (Sender, VerificationGas, CallGas, MaxFee, Paymaster, Entities, UnstakedEntities), (Signature, Timestamp), - ( - Gas, - Opcodes, - ExternalContracts, - StorageAccess, - CallStack, - CodeHashes, - ), + (Gas, Opcodes, ExternalContracts, StorageAccess, CallStack, CodeHashes), >; type UnsafeValidator = StandardUserOperationValidator< M, - ( - Sender, - VerificationGas, - CallGas, - MaxFee, - Paymaster, - Entities, - UnstakedEntities, - ), + (Sender, VerificationGas, CallGas, MaxFee, Paymaster, Entities, UnstakedEntities), (Signature, Timestamp), (), >; @@ -116,9 +93,10 @@ where /// `entry_point` - [EntryPoint](EntryPoint) object. /// `chain` - A [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID. /// `max_verification_gas` - max verification gas that bundler would accept for one user operation -/// `min_priority_fee_per_gas` - min priority fee per gas that bundler would accept for one user operation -/// `max_uos_per_sender` - max user operations that bundler would accept from one sender -/// `gas_increase_perc` - gas increase percentage that bundler would accept for overwriting one user operation +/// `min_priority_fee_per_gas` - min priority fee per gas that bundler would accept for one user +/// operation `max_uos_per_sender` - max user operations that bundler would accept from one sender +/// `gas_increase_perc` - gas increase percentage that bundler would accept for overwriting one user +/// operation /// /// # Returns /// A new [StandardUserOperationValidator](StandardUserOperationValidator). @@ -133,26 +111,15 @@ pub fn new_canonical( chain, ( Sender, - VerificationGas { - max_verification_gas, - }, + VerificationGas { max_verification_gas }, CallGas, - MaxFee { - min_priority_fee_per_gas, - }, + MaxFee { min_priority_fee_per_gas }, Paymaster, Entities, UnstakedEntities, ), (Signature, Timestamp), - ( - Gas, - Opcodes, - ExternalContracts, - StorageAccess, - CallStack, - CodeHashes, - ), + (Gas, Opcodes, ExternalContracts, StorageAccess, CallStack, CodeHashes), ) } @@ -167,13 +134,9 @@ pub fn new_canonical_unsafe( chain, ( Sender, - VerificationGas { - max_verification_gas, - }, + VerificationGas { max_verification_gas }, CallGas, - MaxFee { - min_priority_fee_per_gas, - }, + MaxFee { min_priority_fee_per_gas }, Paymaster, Entities, UnstakedEntities, @@ -197,22 +160,19 @@ where simulation_checks: SimCk, simulation_trace_checks: SimTrCk, ) -> Self { - Self { - entry_point, - chain, - sanity_checks, - simulation_checks, - simulation_trace_checks, - } + Self { entry_point, chain, sanity_checks, simulation_checks, simulation_trace_checks } } - /// Simulates validation of a [UserOperation](UserOperation) via the [simulate_validation](crate::entry_point::EntryPoint::simulate_validation) method of the [entry_point](crate::entry_point::EntryPoint). + /// Simulates validation of a [UserOperation](UserOperation) via the + /// [simulate_validation](crate::entry_point::EntryPoint::simulate_validation) method of the + /// [entry_point](crate::entry_point::EntryPoint). /// /// # Arguments /// `uo` - [UserOperation](UserOperation) to simulate validation on. /// /// # Returns - /// A [SimulateValidationResult](crate::entry_point::SimulateValidationResult) if the simulation was successful, otherwise a [SimulationCheckError](crate::simulation::SimulationCheckError). + /// A [SimulateValidationResult](crate::entry_point::SimulateValidationResult) if the simulation + /// was successful, otherwise a [SimulationCheckError](crate::simulation::SimulationCheckError). async fn simulate_validation( &self, uo: &UserOperation, @@ -232,13 +192,16 @@ where } } - /// Simulates validation of a [UserOperation](UserOperation) via the [simulate_validation_trace](crate::entry_point::EntryPoint::simulate_validation_trace) method of the [entry_point](crate::entry_point::EntryPoint) + /// Simulates validation of a [UserOperation](UserOperation) via the + /// [simulate_validation_trace](crate::entry_point::EntryPoint::simulate_validation_trace) + /// method of the [entry_point](crate::entry_point::EntryPoint) /// /// # Arguments /// `uo` - [UserOperation](UserOperation) to simulate validation on. /// /// # Returns - /// A [GethTrace](ethers::types::GethTrace) if the simulation was successful, otherwise a [SimulationCheckError](crate::simulation::SimulationCheckError). + /// A [GethTrace](ethers::types::GethTrace) if the simulation was successful, otherwise a + /// [SimulationCheckError](crate::simulation::SimulationCheckError). async fn simulate_validation_trace( &self, uo: &UserOperation, @@ -267,17 +230,22 @@ where SimCk: SimulationCheck, SimTrCk: SimulationTraceCheck, { - /// Validates a [UserOperation](UserOperation) via the [simulate_validation](crate::entry_point::EntryPoint::simulate_validation) method of the [entry_point](crate::entry_point::EntryPoint). - /// The function also optionally performs sanity checks and simulation checks if the [UserOperationValidatorMode](UserOperationValidatorMode) contains the respective flags. + /// Validates a [UserOperation](UserOperation) via the + /// [simulate_validation](crate::entry_point::EntryPoint::simulate_validation) method of the + /// [entry_point](crate::entry_point::EntryPoint). The function also optionally performs + /// sanity checks and simulation checks if the + /// [UserOperationValidatorMode](UserOperationValidatorMode) contains the respective flags. /// /// # Arguments /// `uo` - [UserOperation](UserOperation) to validate. - /// `mempool` - [MempoolBox](crate::mempool::MempoolBox) to check for duplicate [UserOperation](UserOperation)s. - /// `reputation` - [ReputationBox](crate::reputation::ReputationBox). + /// `mempool` - [MempoolBox](crate::mempool::MempoolBox) to check for duplicate + /// [UserOperation](UserOperation)s. `reputation` - + /// [ReputationBox](crate::reputation::ReputationBox). /// `mode` - [UserOperationValidatorMode](UserOperationValidatorMode) flag. /// /// # Returns - /// A [UserOperationValidationOutcome](UserOperationValidationOutcome) if the validation was successful, otherwise a [ValidationError](ValidationError). + /// A [UserOperationValidationOutcome](UserOperationValidationOutcome) if the validation was + /// successful, otherwise a [ValidationError](ValidationError). async fn validate_user_operation( &self, uo: &UserOperation, @@ -296,10 +264,7 @@ where let mut out: UserOperationValidationOutcome = Default::default(); if mode.contains(UserOperationValidatorMode::Sanity) { - let sanity_helper = SanityHelper { - entry_point: &self.entry_point, - chain: self.chain, - }; + let sanity_helper = SanityHelper { entry_point: &self.entry_point, chain: self.chain }; self.sanity_checks .check_user_operation(uo, mempool, reputation, &sanity_helper) @@ -313,13 +278,10 @@ where let sim_res = self.simulate_validation(uo).await?; if mode.contains(UserOperationValidatorMode::Simulation) { - let mut sim_helper = SimulationHelper { - simulate_validation_result: &sim_res, - valid_after: None, - }; + let mut sim_helper = + SimulationHelper { simulate_validation_result: &sim_res, valid_after: None }; - self.simulation_checks - .check_user_operation(uo, &mut sim_helper)?; + self.simulation_checks.check_user_operation(uo, &mut sim_helper)?; out.valid_after = sim_helper.valid_after; } @@ -343,11 +305,8 @@ where if mode.contains(UserOperationValidatorMode::SimulationTrace) { debug!("Simulate user operation with trace from {:?}", uo.sender); let geth_trace = self.simulate_validation_trace(uo).await?; - let js_trace: JsTracerFrame = JsTracerFrame::try_from(geth_trace).map_err(|error| { - SimulationCheckError::Validation { - message: error.to_string(), - } - })?; + let js_trace: JsTracerFrame = JsTracerFrame::try_from(geth_trace) + .map_err(|error| SimulationCheckError::Validation { message: error.to_string() })?; let mut sim_helper = SimulationTraceHelper { entry_point: &self.entry_point, diff --git a/crates/p2p/Cargo.toml b/crates/p2p/Cargo.toml index 0af8f2a7..714f3cc8 100644 --- a/crates/p2p/Cargo.toml +++ b/crates/p2p/Cargo.toml @@ -6,39 +6,63 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) Bundler p2p components -""" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-4337) P2P implementation" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/p2p" [dependencies] +# workspace dependencies +silius-primitives = { workspace = true } + +# eth alloy-chains = { workspace = true } -async-trait = "0.1" -delay_map = "0.3.0" discv5 = { workspace = true } ethers = { workspace = true } -eyre = "0.6.8" -futures = "0.3.28" -futures-bounded = "0.2.0" -lazy_static = { workspace = true } -libp2p-mplex = { version = "0.40.0" } -sha2 = "0.10.8" -silius-primitives = { path = "../primitives" } -snap = "1" ssz_rs = { workspace = true } ssz_rs_derive = { workspace = true } -thiserror = "1" + +# p2p +libp2p = { version = "0.52.3", features = [ + "identify", + "yamux", + "noise", + "gossipsub", + "dns", + "tcp", + "tokio", + "secp256k1", + "macros", + "request-response", +] } +libp2p-mplex = { version = "0.40.0" } + +# cryptography +sha2 = "0.10.8" + +# async +async-trait = "0.1" +futures = "0.3.28" +futures-bounded = "0.2.0" + +# tokio tokio = { workspace = true } tokio-util = { version = "0.7.10", features = ["codec"] } + +# misc +delay_map = "0.3.0" +eyre = "0.6.8" +lazy_static = { workspace = true } +snap = "1" +thiserror = { workspace = true } tracing = { workspace = true } unsigned-varint = { version = "0.8.0", features = ["codec"] } -[dependencies.libp2p] -version = "0.52.3" -features = ["identify", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "secp256k1", "macros", "request-response"] - [dev-dependencies] -env_logger = "*" +# eth ethers = { workspace = true } + +# misc +env_logger = "0.10.1" test-log = "0.2.12" -tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"] } +tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } diff --git a/crates/p2p/README.md b/crates/p2p/README.md new file mode 100644 index 00000000..4220ed35 --- /dev/null +++ b/crates/p2p/README.md @@ -0,0 +1,3 @@ +# silius-p2p + +TODO \ No newline at end of file diff --git a/crates/p2p/src/behaviour.rs b/crates/p2p/src/behaviour.rs index 396d6c6e..888d8be1 100644 --- a/crates/p2p/src/behaviour.rs +++ b/crates/p2p/src/behaviour.rs @@ -1,12 +1,12 @@ -use crate::config::Config; -use crate::discovery::{self, Discovery}; -use crate::gossipsub::{create_gossisub, Gossipsub}; -use crate::peer_manager::{PeerManager, PeerManagerEvent}; -use crate::request_response; -use discv5::enr::CombinedKey; -use discv5::Enr; -use libp2p::gossipsub; -use libp2p::swarm::NetworkBehaviour; +use crate::{ + config::Config, + discovery::{self, Discovery}, + gossipsub::{create_gossisub, Gossipsub}, + peer_manager::{PeerManager, PeerManagerEvent}, + request_response, +}; +use discv5::{enr::CombinedKey, Enr}; +use libp2p::{gossipsub, swarm::NetworkBehaviour}; use std::time::Duration; /// The behaviour of the p2p network. @@ -37,12 +37,7 @@ impl Behaviour { let discovery = Discovery::new(enr, key, config)?; let peer_manager = PeerManager::new(ping_interval, target_peers); - Ok(Self { - gossipsub, - reqrep, - discv5: discovery, - peer_manager, - }) + Ok(Self { gossipsub, reqrep, discv5: discovery, peer_manager }) } } diff --git a/crates/p2p/src/config.rs b/crates/p2p/src/config.rs index 58802d43..0206cbe7 100644 --- a/crates/p2p/src/config.rs +++ b/crates/p2p/src/config.rs @@ -98,14 +98,8 @@ impl Default for Config { impl Config { pub fn to_listen_config(&self) -> ListenConfig { match &self.listen_addr { - ListenAddress::Ipv4(v) => ListenConfig::Ipv4 { - ip: v.addr, - port: v.udp_port, - }, - ListenAddress::Ipv6(v) => ListenConfig::Ipv6 { - ip: v.addr, - port: v.udp_port, - }, + ListenAddress::Ipv4(v) => ListenConfig::Ipv4 { ip: v.addr, port: v.udp_port }, + ListenAddress::Ipv6(v) => ListenConfig::Ipv6 { ip: v.addr, port: v.udp_port }, ListenAddress::Dual(ipv4, ipv6) => ListenConfig::DualStack { ipv4: ipv4.addr, ipv4_port: ipv4.udp_port, diff --git a/crates/p2p/src/discovery.rs b/crates/p2p/src/discovery.rs index 535dbb65..bcb433dc 100644 --- a/crates/p2p/src/discovery.rs +++ b/crates/p2p/src/discovery.rs @@ -70,9 +70,7 @@ impl Discovery { Box::new(move |enr: &Enr| enr.tcp4().is_some() || enr.tcp6().is_some()); // Build the future - let query_future = self - .discovery - .find_node_predicate(random_node, predicate, target_peers); + let query_future = self.discovery.find_node_predicate(random_node, predicate, target_peers); self.active_queries.push(Box::pin(query_future)); } @@ -119,11 +117,11 @@ impl NetworkBehaviour for Discovery { while let Poll::Ready(Some(event)) = stream.poll_recv(cx) { match event { Discv5Event::Discovered(_) => {} - Discv5Event::EnrAdded { .. } - | Discv5Event::NodeInserted { .. } - | Discv5Event::SessionEstablished(_, _) - | Discv5Event::SocketUpdated(_) - | Discv5Event::TalkRequest(_) => {} + Discv5Event::EnrAdded { .. } | + Discv5Event::NodeInserted { .. } | + Discv5Event::SessionEstablished(_, _) | + Discv5Event::SocketUpdated(_) | + Discv5Event::TalkRequest(_) => {} } } } diff --git a/crates/p2p/src/gossipsub.rs b/crates/p2p/src/gossipsub.rs index dfcb7c10..79bd472b 100644 --- a/crates/p2p/src/gossipsub.rs +++ b/crates/p2p/src/gossipsub.rs @@ -3,7 +3,7 @@ use libp2p::gossipsub::{ RawMessage, TopicHash, ValidationMode, WhitelistSubscriptionFilter, }; use sha2::{Digest, Sha256}; -use silius_primitives::consts::p2p::{ +use silius_primitives::constants::p2p::{ MAX_GOSSIP_SNAP_SIZE, MESSAGE_DOMAIN_VALID_SNAPPY, SSZ_SNAPPY_ENCODING, TOPIC_PREFIX, USER_OPS_WITH_ENTRY_POINT_TOPIC, }; @@ -24,17 +24,13 @@ pub struct SnappyTransform { impl SnappyTransform { pub fn new(max_size_per_message: usize) -> Self { - SnappyTransform { - max_size_per_message, - } + SnappyTransform { max_size_per_message } } } impl Default for SnappyTransform { fn default() -> Self { - SnappyTransform { - max_size_per_message: MAX_GOSSIP_SNAP_SIZE, - } + SnappyTransform { max_size_per_message: MAX_GOSSIP_SNAP_SIZE } } } @@ -101,10 +97,10 @@ pub fn message_id_fn(message: &Message) -> MessageId { let topic_len_bytes = topic_bytes.len().to_le_bytes(); let mut vec: Vec = Vec::with_capacity( - MESSAGE_DOMAIN_VALID_SNAPPY.len() - + topic_len_bytes.len() - + topic_bytes.len() - + message.data.len(), + MESSAGE_DOMAIN_VALID_SNAPPY.len() + + topic_len_bytes.len() + + topic_bytes.len() + + message.data.len(), ); vec.extend_from_slice(&MESSAGE_DOMAIN_VALID_SNAPPY); vec.extend_from_slice(&topic_len_bytes); @@ -131,9 +127,7 @@ pub fn create_gossisub(mempool_ids: Vec) -> Result, - UnboundedSender, -)>; +pub type EntrypointChannels = + Vec<(Chain, Address, UnboundedReceiver<(UserOperation, U256)>, UnboundedSender)>; /// P2P network struct that holds the libp2p Swarm /// Other components should interact with Network directly instead of behaviour @@ -132,11 +128,9 @@ impl Network { yamux_config.set_window_update_mode(libp2p::yamux::WindowUpdateMode::on_read()); let swarm = SwarmBuilder::with_existing_identity(key) .with_tokio() - .with_tcp( - libp2p::tcp::Config::default().nodelay(true), - noise::Config::new, - || upgrade::SelectUpgrade::new(yamux_config, mplex_config), - ) + .with_tcp(libp2p::tcp::Config::default().nodelay(true), noise::Config::new, || { + upgrade::SelectUpgrade::new(yamux_config, mplex_config) + }) .expect("building p2p transport failed") .with_behaviour(|_| behaviour) .expect("building p2p behaviour failed") @@ -148,21 +142,13 @@ impl Network { ..Default::default() // FIXME: when mempool id of canonical will be known }; - Ok(Self { - swarm, - entrypoint_channels, - metadata, - }) + Ok(Self { swarm, entrypoint_channels, metadata }) } /// handle gossipsub event fn handle_gossipsub_event(&self, event: Box) -> Option { match *event { - gossipsub::Event::Message { - propagation_source, - message_id, - message, - } => { + gossipsub::Event::Message { propagation_source, message_id, message } => { let userops = match UserOperationsWithEntryPoint::deserialize(message.data.as_ref()) { Ok(userops) => userops, @@ -171,21 +157,19 @@ impl Network { return None; } }; - self.entrypoint_channels - .iter() - .find_map(|(_, ep, _, new_coming_uos_ch)| { - if *ep == userops.entrypoint_address() { - for user_op in userops.clone().user_operations().into_iter() { - new_coming_uos_ch - .unbounded_send(user_op) - .expect("new useop channel should be open all the time"); - } - Some(()) - } else { - warn!("Received unsupported entrypoint userops {ep:?} from p2p"); - None + self.entrypoint_channels.iter().find_map(|(_, ep, _, new_coming_uos_ch)| { + if *ep == userops.entrypoint_address() { + for user_op in userops.clone().user_operations().into_iter() { + new_coming_uos_ch + .unbounded_send(user_op) + .expect("new useop channel should be open all the time"); } - }); + Some(()) + } else { + warn!("Received unsupported entrypoint userops {ep:?} from p2p"); + None + } + }); let message = PubsubMessage::UserOps(userops); Some(NetworkEvent::PubsubMessage { @@ -208,36 +192,25 @@ impl Network { /// handle reqrep event fn handle_reqrep_event(&self, event: request_response::Event) -> Option { match event { - request_response::Event::Request { - peer_id, - request, - response_sender, - .. - } => match request { - Request::Ping(_ping) => { - // TODO: need to update metadata of peer (based on ping value) - let response = Response::Pong(Pong::new(self.metadata.seq_number)); - response_sender - .send(response) - .expect("channel should exist"); - None - } - Request::GetMetadata(_) => { - let response = Response::Metadata(self.metadata.clone()); - response_sender - .send(response) - .expect("channel should exist"); - None + request_response::Event::Request { peer_id, request, response_sender, .. } => { + match request { + Request::Ping(_ping) => { + // TODO: need to update metadata of peer (based on ping value) + let response = Response::Pong(Pong::new(self.metadata.seq_number)); + response_sender.send(response).expect("channel should exist"); + None + } + Request::GetMetadata(_) => { + let response = Response::Metadata(self.metadata.clone()); + response_sender.send(response).expect("channel should exist"); + None + } + _ => Some(NetworkEvent::RequestMessage { peer_id, request, response_sender }), } - _ => Some(NetworkEvent::RequestMessage { - peer_id, - request, - response_sender, - }), - }, - request_response::Event::Response { - peer_id, response, .. - } => Some(NetworkEvent::ResponseMessage { peer_id, response }), + } + request_response::Event::Response { peer_id, response, .. } => { + Some(NetworkEvent::ResponseMessage { peer_id, response }) + } _ => None, } } @@ -254,12 +227,9 @@ impl Network { self.send_request(&peer, Request::Ping(Ping::new(self.metadata.seq_number))); None } - PeerManagerEvent::PeerConnectedIncoming(peer) - | PeerManagerEvent::PeerConnectedOutgoing(peer) => { - self.swarm - .behaviour_mut() - .gossipsub - .add_explicit_peer(&peer); + PeerManagerEvent::PeerConnectedIncoming(peer) | + PeerManagerEvent::PeerConnectedOutgoing(peer) => { + self.swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer); Some(NetworkEvent::PeerConnected(peer)) } @@ -345,14 +315,9 @@ impl Network { user_ops: UserOperationsWithEntryPoint, ) -> Result { let mut buf = Vec::new(); - let _ = user_ops - .serialize(&mut buf) - .expect("ssz of user ops serialization failed"); + let _ = user_ops.serialize(&mut buf).expect("ssz of user ops serialization failed"); let topic_hash: TopicHash = topic(user_ops.chain().canonical_mempool_id()).into(); - self.swarm - .behaviour_mut() - .gossipsub - .publish(topic_hash, buf) + self.swarm.behaviour_mut().gossipsub.publish(topic_hash, buf) } /// Dial a peer. @@ -372,10 +337,7 @@ impl Network { /// Subscribe to a topic. pub fn subscribe(&mut self, mempool_id: &str) -> Result { - self.swarm - .behaviour_mut() - .gossipsub - .subscribe(&topic(mempool_id)) + self.swarm.behaviour_mut().gossipsub.subscribe(&topic(mempool_id)) } /// Return the nodes local ENR. @@ -390,10 +352,7 @@ impl Network { /// Send a request to a peer. pub fn send_request(&mut self, peer: &PeerId, request: Request) -> RequestId { - self.swarm - .behaviour_mut() - .reqrep - .send_request(peer, request) + self.swarm.behaviour_mut().reqrep.send_request(peer, request) } /// Send a response to a peer. @@ -402,9 +361,6 @@ impl Network { response_channel: oneshot::Sender, response: Response, ) -> Result<(), Response> { - self.swarm - .behaviour_mut() - .reqrep - .send_response(response_channel, response) + self.swarm.behaviour_mut().reqrep.send_response(response_channel, response) } } diff --git a/crates/p2p/src/peer_manager/mod.rs b/crates/p2p/src/peer_manager/mod.rs index 314679d0..12d4c175 100644 --- a/crates/p2p/src/peer_manager/mod.rs +++ b/crates/p2p/src/peer_manager/mod.rs @@ -53,8 +53,7 @@ impl NetworkBehaviour for PeerManager { fn on_swarm_event(&mut self, event: libp2p::swarm::FromSwarm) { if let libp2p::swarm::FromSwarm::ConnectionClosed(close_info) = event { self.peer_db.disconnect(close_info.peer_id); - self.events - .push_back(PeerManagerEvent::PeerDisconnected(close_info.peer_id)); + self.events.push_back(PeerManagerEvent::PeerDisconnected(close_info.peer_id)); } } @@ -75,8 +74,7 @@ impl NetworkBehaviour for PeerManager { ) -> Result, libp2p::swarm::ConnectionDenied> { self.peer_db.new_connected(peer); self.ping_peers.insert(peer); - self.events - .push_back(PeerManagerEvent::PeerConnectedIncoming(peer)); + self.events.push_back(PeerManagerEvent::PeerConnectedIncoming(peer)); Ok(ConnectionHandler) } @@ -89,8 +87,7 @@ impl NetworkBehaviour for PeerManager { ) -> Result, libp2p::swarm::ConnectionDenied> { self.peer_db.new_connected(peer); self.ping_peers.insert(peer); - self.events - .push_back(PeerManagerEvent::PeerConnectedOutgoing(peer)); + self.events.push_back(PeerManagerEvent::PeerConnectedOutgoing(peer)); Ok(ConnectionHandler) } diff --git a/crates/p2p/src/peer_manager/peerdb.rs b/crates/p2p/src/peer_manager/peerdb.rs index 4a9b56a0..c362967f 100644 --- a/crates/p2p/src/peer_manager/peerdb.rs +++ b/crates/p2p/src/peer_manager/peerdb.rs @@ -19,9 +19,7 @@ pub struct PeerDB { impl PeerDB { pub fn new() -> Self { - Self { - peers: HashMap::new(), - } + Self { peers: HashMap::new() } } pub fn new_connected(&mut self, peer_id: PeerId) { diff --git a/crates/p2p/src/request_response/behaviour.rs b/crates/p2p/src/request_response/behaviour.rs index b7dcae2c..33f4d635 100644 --- a/crates/p2p/src/request_response/behaviour.rs +++ b/crates/p2p/src/request_response/behaviour.rs @@ -99,9 +99,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { - Self { - request_timeout: Duration::from_secs(10), - } + Self { request_timeout: Duration::from_secs(10) } } } pub struct Behaviour { @@ -141,19 +139,11 @@ impl Behaviour { /// Send a request to the given peer. pub fn send_request(&mut self, peer: &PeerId, request: Request) -> RequestId { let request_id = self.next_request_id(); - let request = OutboundInfo { - request, - request_id, - }; + let request = OutboundInfo { request, request_id }; if let Some(request) = self.try_send_request(peer, request) { - self.pending_events.push_back(ToSwarm::Dial { - opts: DialOpts::peer_id(*peer).build(), - }); - self.pending_outbound_requests - .entry(*peer) - .or_default() - .push(request); + self.pending_events.push_back(ToSwarm::Dial { opts: DialOpts::peer_id(*peer).build() }); + self.pending_outbound_requests.entry(*peer).or_default().push(request); } request_id @@ -233,12 +223,9 @@ impl Behaviour { fn on_connection_closed( &mut self, - ConnectionClosed { - peer_id, - connection_id, - remaining_established, - .. - }: ConnectionClosed<::ConnectionHandler>, + ConnectionClosed { peer_id, connection_id, remaining_established, .. }: ConnectionClosed< + ::ConnectionHandler, + >, ) { let connections = self .connected @@ -257,21 +244,19 @@ impl Behaviour { } for request_id in connection.pending_outbound_responses { - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::InboundFailure { - peer_id, - request_id, - error: InboundFailure::ConnectionClosed, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::InboundFailure { + peer_id, + request_id, + error: InboundFailure::ConnectionClosed, + })); } for request_id in connection.pending_inbound_responses { - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { - peer_id, - request_id, - error: OutboundFailure::ConnectionClosed, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { + peer_id, + request_id, + error: OutboundFailure::ConnectionClosed, + })); } } @@ -285,12 +270,11 @@ impl Behaviour { // another, concurrent dialing attempt ongoing. if let Some(pending) = self.pending_outbound_requests.remove(&peer_id) { for request in pending { - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { - peer_id, - request_id: request.request_id, - error: OutboundFailure::DialFailure, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { + peer_id, + request_id: request.request_id, + error: OutboundFailure::DialFailure, + })); } } } @@ -307,11 +291,7 @@ impl NetworkBehaviour for Behaviour { _local_addr: &libp2p::Multiaddr, _remote_addr: &libp2p::Multiaddr, ) -> Result, ConnectionDenied> { - Ok(Handler::new( - connection_id, - self.config.request_timeout, - self.next_inbound_id.clone(), - )) + Ok(Handler::new(connection_id, self.config.request_timeout, self.next_inbound_id.clone())) } fn handle_established_outbound_connection( @@ -321,11 +301,7 @@ impl NetworkBehaviour for Behaviour { _addr: &libp2p::Multiaddr, _role_override: libp2p::core::Endpoint, ) -> Result, ConnectionDenied> { - Ok(Handler::new( - connection_id, - self.config.request_timeout, - self.next_inbound_id.clone(), - )) + Ok(Handler::new(connection_id, self.config.request_timeout, self.next_inbound_id.clone())) } fn handle_pending_inbound_connection( @@ -354,19 +330,9 @@ impl NetworkBehaviour for Behaviour { event: THandlerOutEvent, ) { match event { - HandlerEvent::Request { - request, - request_id, - response_sender, - } => { - let message = Event::Request { - peer_id, - request_id, - request, - response_sender, - }; - self.pending_events - .push_back(ToSwarm::GenerateEvent(message)); + HandlerEvent::Request { request, request_id, response_sender } => { + let message = Event::Request { peer_id, request_id, request, response_sender }; + self.pending_events.push_back(ToSwarm::GenerateEvent(message)); match self.get_connection_mut(&peer_id, connection_id) { Some(connection) => { @@ -384,75 +350,63 @@ impl NetworkBehaviour for Behaviour { } } } - HandlerEvent::Response { - response, - request_id, - } => { + HandlerEvent::Response { response, request_id } => { self.remove_pending_inbound_response(&peer_id, connection_id, &request_id); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::Response { - peer_id, - request_id, - response, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::Response { + peer_id, + request_id, + response, + })); } HandlerEvent::InboundTimeout(request_id) => { self.remove_pending_inbound_response(&peer_id, connection_id, &request_id); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::InboundFailure { - peer_id, - request_id, - error: InboundFailure::Timeout, - })) + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::InboundFailure { + peer_id, + request_id, + error: InboundFailure::Timeout, + })) } HandlerEvent::InboundError { request_id, error } => { self.remove_pending_inbound_response(&peer_id, connection_id, &request_id); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::InboundFailure { - peer_id, - request_id, - error: InboundFailure::BoundError(error), - })) + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::InboundFailure { + peer_id, + request_id, + error: InboundFailure::BoundError(error), + })) } HandlerEvent::OutboundError { request_id, error } => { self.remove_pending_outbound_response(&peer_id, connection_id, request_id); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { - peer_id, - request_id, - error: OutboundFailure::BoundError(error), - })) + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { + peer_id, + request_id, + error: OutboundFailure::BoundError(error), + })) } HandlerEvent::DialUpgradeTimeout(_) => {} HandlerEvent::ResponseSent(request_id) => { self.remove_pending_outbound_response(&peer_id, connection_id, request_id); self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::ResponseSent { - peer_id, - request_id, - })); + .push_back(ToSwarm::GenerateEvent(Event::ResponseSent { peer_id, request_id })); } HandlerEvent::ResponseOmission(request_id) => { self.remove_pending_outbound_response(&peer_id, connection_id, request_id); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::InboundFailure { - peer_id, - request_id, - error: InboundFailure::ResponseOmission, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::InboundFailure { + peer_id, + request_id, + error: InboundFailure::ResponseOmission, + })); } HandlerEvent::OutboundTimeout(request_id) => { self.remove_pending_outbound_response(&peer_id, connection_id, request_id); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { - peer_id, - request_id, - error: OutboundFailure::Timeout, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { + peer_id, + request_id, + error: OutboundFailure::Timeout, + })); } HandlerEvent::OutboundUnsurpportedProtocol(request_id) => { let removed = @@ -462,12 +416,11 @@ impl NetworkBehaviour for Behaviour { "Expect request_id to be pending before failing to connect.", ); - self.pending_events - .push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { - peer_id, - request_id, - error: OutboundFailure::UnsupportedProtocols, - })); + self.pending_events.push_back(ToSwarm::GenerateEvent(Event::OutboundFailure { + peer_id, + request_id, + error: OutboundFailure::UnsupportedProtocols, + })); } } } @@ -481,9 +434,8 @@ impl NetworkBehaviour for Behaviour { .push(Connection::new(connection_established.connection_id)); if connection_established.other_established == 0 { - if let Some(pending) = self - .pending_outbound_requests - .remove(&connection_established.peer_id) + if let Some(pending) = + self.pending_outbound_requests.remove(&connection_established.peer_id) { for request in pending { let request = diff --git a/crates/p2p/src/request_response/handler.rs b/crates/p2p/src/request_response/handler.rs index d298ec0f..7085b020 100644 --- a/crates/p2p/src/request_response/handler.rs +++ b/crates/p2p/src/request_response/handler.rs @@ -13,9 +13,8 @@ use futures::{ channel::oneshot::{self, Receiver, Sender}, future::BoxFuture, stream::FuturesUnordered, - FutureExt, StreamExt, TryFutureExt, + AsyncReadExt, AsyncWriteExt, FutureExt, StreamExt, TryFutureExt, }; -use futures::{AsyncReadExt, AsyncWriteExt}; use libp2p::{ bytes::BytesMut, swarm::{ @@ -59,27 +58,14 @@ pub struct OutboundInfo { /// Events emitted by the handler. #[derive(Debug)] pub enum HandlerEvent { - Request { - request: Request, - request_id: RequestId, - response_sender: oneshot::Sender, - }, - Response { - response: Response, - request_id: RequestId, - }, + Request { request: Request, request_id: RequestId, response_sender: oneshot::Sender }, + Response { response: Response, request_id: RequestId }, ResponseSent(RequestId), ResponseOmission(RequestId), InboundTimeout(RequestId), OutboundTimeout(RequestId), - InboundError { - request_id: RequestId, - error: BoundError, - }, - OutboundError { - request_id: RequestId, - error: BoundError, - }, + InboundError { request_id: RequestId, error: BoundError }, + OutboundError { request_id: RequestId, error: BoundError }, DialUpgradeTimeout(RequestId), OutboundUnsurpportedProtocol(RequestId), } @@ -142,18 +128,11 @@ impl Handler { >, ) { let (mut socket, protocol_id) = protocol; - let InboundInfo { - request_sender, - response_receiver, - request_id, - } = info; + let InboundInfo { request_sender, response_receiver, request_id } = info; let recv = async move { let mut data = Vec::new(); let socket_mut = &mut socket; - socket_mut - .take(REQUEST_SIZE_MAXIMUM) - .read_to_end(&mut data) - .await?; + socket_mut.take(REQUEST_SIZE_MAXIMUM).read_to_end(&mut data).await?; trace!("Inbound bytes: {:?}", data); trace!("Received {:?} bytes", data.len()); @@ -222,9 +201,8 @@ impl Handler { // encode let mut writer = snap::write::FrameEncoder::new(vec![]); writer.write_all(&ssz_bytes)?; - let compressed_data = writer - .into_inner() - .map_err(|e| BoundError::IoError(e.into_error()))?; + let compressed_data = + writer.into_inner().map_err(|e| BoundError::IoError(e.into_error()))?; bytes.extend_from_slice(&compressed_data); trace!("Inbound sending {:?}", bytes.to_vec()); @@ -242,11 +220,7 @@ impl Handler { } }; - if self - .worker_streams - .try_push(BoundTypeId::Inbound(request_id), recv.boxed()) - .is_err() - { + if self.worker_streams.try_push(BoundTypeId::Inbound(request_id), recv.boxed()).is_err() { warn!("Dropping inbound stream because we are at capacity") } } @@ -260,10 +234,7 @@ impl Handler { >, ) { let (mut socket, protocol_id) = protocol; - let OutboundInfo { - request, - request_id, - } = info; + let OutboundInfo { request, request_id } = info; let send = async move { trace!("Outbound {:?}", request); let mut buffer = Vec::new(); @@ -294,9 +265,8 @@ impl Handler { // encode payload let mut writer = snap::write::FrameEncoder::new(vec![]); writer.write_all(&buffer)?; - let compressed_data = writer - .into_inner() - .map_err(|e| BoundError::IoError(e.into_error()))?; + let compressed_data = + writer.into_inner().map_err(|e| BoundError::IoError(e.into_error()))?; bytes.extend_from_slice(&compressed_data); trace!("Outbound bytes {:?}", bytes.to_vec()); @@ -305,10 +275,7 @@ impl Handler { socket_mut.close().await?; let mut compressed_response = Vec::new(); - socket_mut - .take(RESPONSE_SIZE_MAXIMUM) - .read_to_end(&mut compressed_response) - .await?; + socket_mut.take(RESPONSE_SIZE_MAXIMUM).read_to_end(&mut compressed_response).await?; trace!("Outbound received {:?}", compressed_response); @@ -345,17 +312,10 @@ impl Handler { } }; - Ok(HandlerEvent::Response { - response, - request_id, - }) + Ok(HandlerEvent::Response { response, request_id }) }; - if self - .worker_streams - .try_push(BoundTypeId::Outbound(request_id), send.boxed()) - .is_err() - { + if self.worker_streams.try_push(BoundTypeId::Outbound(request_id), send.boxed()).is_err() { warn!("Dropping inbound stream because we are at capacity") } } @@ -385,11 +345,8 @@ impl ConnectionHandler for Handler { let request_id = RequestId(self.inbound_request_id.fetch_add(1, Ordering::Relaxed)); - let inbound_info = InboundInfo { - request_sender: rq_send, - response_receiver: rs_recv, - request_id, - }; + let inbound_info = + InboundInfo { request_sender: rq_send, response_receiver: rs_recv, request_id }; self.inbound.push( rq_recv @@ -428,21 +385,17 @@ impl ConnectionHandler for Handler { StreamUpgradeError::Timeout => self .pending_events .push_back(HandlerEvent::DialUpgradeTimeout(error.info.request_id)), - StreamUpgradeError::NegotiationFailed => { - self.pending_events - .push_back(HandlerEvent::OutboundUnsurpportedProtocol( - error.info.request_id, - )) + StreamUpgradeError::NegotiationFailed => self + .pending_events + .push_back(HandlerEvent::OutboundUnsurpportedProtocol(error.info.request_id)), + dial_error => { + warn!("outbound stream with {:?} failed with {dial_error:?}", error.info) } - dial_error => warn!( - "outbound stream with {:?} failed with {dial_error:?}", - error.info - ), }, - ConnectionEvent::ListenUpgradeError(_) - | ConnectionEvent::LocalProtocolsChange(_) - | ConnectionEvent::RemoteProtocolsChange(_) - | ConnectionEvent::AddressChange(_) => {} + ConnectionEvent::ListenUpgradeError(_) | + ConnectionEvent::LocalProtocolsChange(_) | + ConnectionEvent::RemoteProtocolsChange(_) | + ConnectionEvent::AddressChange(_) => {} } } @@ -486,24 +439,14 @@ impl ConnectionHandler for Handler { } if let Some(event) = self.pending_events.pop_front() { - return Poll::Ready(libp2p::swarm::ConnectionHandlerEvent::NotifyBehaviour( - event, - )); + return Poll::Ready(libp2p::swarm::ConnectionHandlerEvent::NotifyBehaviour(event)); }; while let Poll::Ready(Some(result)) = self.inbound.poll_next_unpin(cx) { match result { - Ok(RequestContainer { - request, - request_id, - response_sender, - }) => { + Ok(RequestContainer { request, request_id, response_sender }) => { return Poll::Ready(libp2p::swarm::ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Request { - request, - response_sender, - request_id, - }, + HandlerEvent::Request { request, response_sender, request_id }, )); } Err(oneshot::Canceled) => {} @@ -511,15 +454,13 @@ impl ConnectionHandler for Handler { } if let Some(request) = self.outbound.pop_front() { - return Poll::Ready( - libp2p::swarm::ConnectionHandlerEvent::OutboundSubstreamRequest { - protocol: SubstreamProtocol::new( - OutboundRepUpgrade(request.clone().request), - request, - ) - .with_timeout(self.substream_timeout), - }, - ); + return Poll::Ready(libp2p::swarm::ConnectionHandlerEvent::OutboundSubstreamRequest { + protocol: SubstreamProtocol::new( + OutboundRepUpgrade(request.clone().request), + request, + ) + .with_timeout(self.substream_timeout), + }); }; Poll::Pending diff --git a/crates/p2p/src/request_response/protocol.rs b/crates/p2p/src/request_response/protocol.rs index 4061b237..5ade6dc5 100644 --- a/crates/p2p/src/request_response/protocol.rs +++ b/crates/p2p/src/request_response/protocol.rs @@ -1,5 +1,5 @@ use lazy_static::lazy_static; -use silius_primitives::consts::p2p::REQREP_PROTOCOL_PREFIX; +use silius_primitives::constants::p2p::REQREP_PROTOCOL_PREFIX; use std::fmt::Display; lazy_static! { @@ -58,12 +58,7 @@ impl ProtocolId { Version::V1, Encoding::SSZSnappy ); - Self { - message_name, - version: Version::V1, - encoding: Encoding::SSZSnappy, - protocol_id, - } + Self { message_name, version: Version::V1, encoding: Encoding::SSZSnappy, protocol_id } } } diff --git a/crates/p2p/src/tests/pubsub.rs b/crates/p2p/src/tests/pubsub.rs index 0c815bba..cc18be08 100644 --- a/crates/p2p/src/tests/pubsub.rs +++ b/crates/p2p/src/tests/pubsub.rs @@ -32,11 +32,7 @@ async fn pubsub_msg() -> eyre::Result<()> { let receiver_fut = async { loop { match peer2.next_event().await { - NetworkEvent::PubsubMessage { - source_peer, - message, - .. - } => { + NetworkEvent::PubsubMessage { source_peer, message, .. } => { assert_eq!(source_peer, peer1_id); assert_eq!(message, PubsubMessage::UserOps(uo_entrypoint.clone())); return; diff --git a/crates/p2p/src/tests/req_rep.rs b/crates/p2p/src/tests/req_rep.rs index 43035222..d74ec7ac 100644 --- a/crates/p2p/src/tests/req_rep.rs +++ b/crates/p2p/src/tests/req_rep.rs @@ -35,17 +35,11 @@ async fn reqrep_case(request_case: Request, response_case: Response) -> eyre::Re let receiver_fut = async { loop { match peer2.next_event().await { - NetworkEvent::RequestMessage { - request, - response_sender, - peer_id, - } => { + NetworkEvent::RequestMessage { request, response_sender, peer_id } => { println!("received request"); assert_eq!(request, request_case.clone()); assert_eq!(peer1_id, peer_id); - peer2 - .send_response(response_sender, response_case.clone()) - .unwrap(); + peer2.send_response(response_sender, response_case.clone()).unwrap(); } NetworkEvent::ResponseMessage { .. } => { panic!("Unexpected response") @@ -67,11 +61,7 @@ async fn reqrep_case(request_case: Request, response_case: Response) -> eyre::Re #[tokio::test] async fn reqrep_status() -> eyre::Result<()> { - reqrep_case( - Request::Status(Status::default()), - Response::Status(Status::default()), - ) - .await?; + reqrep_case(Request::Status(Status::default()), Response::Status(Status::default())).await?; Ok(()) } @@ -87,21 +77,13 @@ async fn reqrep_goodbye() -> eyre::Result<()> { #[tokio::test] async fn reqrep_ping_pong() -> eyre::Result<()> { - reqrep_case( - Request::Ping(Default::default()), - Response::Pong(Default::default()), - ) - .await?; + reqrep_case(Request::Ping(Default::default()), Response::Pong(Default::default())).await?; Ok(()) } #[tokio::test] async fn reqrep_metadata() -> eyre::Result<()> { - reqrep_case( - Request::GetMetadata(GetMetadata), - Response::Metadata(Default::default()), - ) - .await?; + reqrep_case(Request::GetMetadata(GetMetadata), Response::Metadata(Default::default())).await?; Ok(()) } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index f741f4da..2c669e99 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -6,28 +6,36 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler commonly used types -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-4337) primitive types" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/primitives" [dependencies] +# eth alloy-chains = { workspace = true } +ethers = { workspace = true } +ssz_rs = { workspace = true } +ssz_rs_derive = { workspace = true } + +# async async-stream = { workspace = true } +futures-util = { workspace = true } + +# tokio +tokio = { workspace = true } + +# misc educe = { version = "0.4", features = ["Debug", "Default"] } -ethers = { workspace = true } expanded-pathbuf = { workspace = true } eyre = { workspace = true } -futures-util = { workspace = true } lazy_static = { workspace = true } -rustc-hex = "^2.0.1" +rustc-hex = "2.0.1" serde = "1" serde-hex = "0.1.0" serde_json = { workspace = true } -ssz_rs = { workspace = true } -ssz_rs_derive = { workspace = true } strum = "0.24" strum_macros = "0.24" -tokio = { workspace = true } tracing = { workspace = true } [features] diff --git a/crates/primitives/README.md b/crates/primitives/README.md new file mode 100644 index 00000000..d66507bc --- /dev/null +++ b/crates/primitives/README.md @@ -0,0 +1,3 @@ +# silius-primitives + +TODO \ No newline at end of file diff --git a/crates/primitives/src/bundler.rs b/crates/primitives/src/bundler.rs index 4c3ac8ae..964f828e 100644 --- a/crates/primitives/src/bundler.rs +++ b/crates/primitives/src/bundler.rs @@ -1,24 +1,25 @@ +//! Bundler-related primitives + use serde::Deserialize; use strum_macros::{EnumString, EnumVariantNames}; -/// Default time interval for auto bundling mode (in seconds) -pub const DEFAULT_BUNDLE_INTERVAL: u64 = 10; - -/// Bundling modes +/// Bundler modes #[derive(Debug, Deserialize)] pub enum Mode { + /// Sends bundles automatically every x seconds #[serde(rename = "auto")] - Auto, + Auto(u64), + /// Sends bundles upon request #[serde(rename = "manual")] Manual, } -/// The `SendBundleMode` determines whether to send the bundle to a Ethereum execution client or to Flashbots relay +/// Determines the mode how bundler sends the bundle #[derive(Clone, Copy, Debug, EnumString, EnumVariantNames, PartialEq, Eq)] #[strum(serialize_all = "kebab_case")] -pub enum SendBundleMode { - /// Send the bundle to a Ethereum execution client +pub enum SendStrategy { + /// Sends the bundle to the Ethereum execution client EthClient, - /// Send the bundle to Flashbots relay + /// Sends the bundle to the Flashbots relay Flashbots, } diff --git a/crates/primitives/src/chain.rs b/crates/primitives/src/chain.rs index 0aeaa682..183ff9f6 100644 --- a/crates/primitives/src/chain.rs +++ b/crates/primitives/src/chain.rs @@ -1,4 +1,6 @@ -use crate::consts::supported_chains::{DEV, GOERLI, MUMBAI, SEPOLIA}; +//! Chain extensions + +use crate::constants::supported_chains::{DEV, GOERLI, MUMBAI, SEPOLIA}; use alloy_chains::Chain; pub trait ChainExt { @@ -12,7 +14,7 @@ impl ChainExt for Chain { GOERLI => "QmTmj4cizhWpEFCCqk5dP67yws7R2PPgCtb2bd2RgVPCbF", SEPOLIA => "QmdDwVFoEEcgv5qnaTB8ncnXGMnqrhnA5nYpRr4ouWe4AT", MUMBAI => "QmQfRyE9iVTBqZ17hPSP4tuMzaez83Y5wD874ymyRtj9VE", - _ => panic!("Chain {self:?} canonical mempool is not supported"), + _ => panic!("Canonical mempool on chain {self:?} is not supported!"), } } } diff --git a/crates/primitives/src/consts.rs b/crates/primitives/src/constants.rs similarity index 54% rename from crates/primitives/src/consts.rs rename to crates/primitives/src/constants.rs index 3a48b184..24632962 100644 --- a/crates/primitives/src/consts.rs +++ b/crates/primitives/src/constants.rs @@ -1,66 +1,67 @@ -/// Entry point +//! Account abstraction (ERC-4337)-related constants + +/// Entry point smart contract pub mod entry_point { + /// Address of the entry point smart contract pub const ADDRESS: &str = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; + /// Version of the entry point smart contract pub const VERSION: &str = "0.6.0"; } -/// RPC error codes -pub mod rpc_error_codes { - pub const VALIDATION: i32 = -32500; - pub const PAYMASTER: i32 = -32501; - pub const OPCODE: i32 = -32502; - pub const EXPIRATION: i32 = -32503; - pub const ENTITY_BANNED_OR_THROTTLED: i32 = -32504; - pub const STAKE_TOO_LOW: i32 = -32505; - pub const SIGNATURE_AGGREGATOR: i32 = -32506; - pub const SIGNATURE: i32 = -32507; - pub const EXECUTION: i32 = -32521; - pub const USER_OPERATION_HASH: i32 = -32601; - pub const SANITY_CHECK: i32 = -32602; +/// Bundler +pub mod bundler { + /// Default time interval for auto bundling mode (in seconds) + pub const BUNDLE_INTERVAL: u64 = 10; } -/// Entities -pub mod entities { - // 0 - factory, 1 - sender/account, 2 - paymaster - pub const NUMBER_LEVELS: usize = 3; +/// User operation mempool +pub mod mempool { + /// Percentage increase of gas price to replace a user operation in the mempool + pub const GAS_INCREASE_PERC: u64 = 10; + /// Depth scan when searching for previous user operations + pub const LATEST_SCAN_DEPTH: u64 = 1000; +} - pub const FACTORY: &str = "factory"; - pub const SENDER: &str = "account"; - pub const PAYMASTER: &str = "paymaster"; +/// User operation validation +pub mod validation { + /// Entities (factory, sender/account, paymaster, aggregator) + pub mod entities { + // 0 - factory, 1 - sender/account, 2 - paymaster + pub const NUMBER_OF_LEVELS: usize = 3; - pub const FACTORY_LEVEL: usize = 0; - pub const SENDER_LEVEL: usize = 1; - pub const PAYMASTER_LEVEL: usize = 2; + pub const FACTORY: &str = "factory"; + pub const SENDER: &str = "account"; + pub const PAYMASTER: &str = "paymaster"; - pub const LEVEL_TO_ENTITY: [&str; NUMBER_LEVELS] = [FACTORY, SENDER, PAYMASTER]; -} + pub const FACTORY_LEVEL: usize = 0; + pub const SENDER_LEVEL: usize = 1; + pub const PAYMASTER_LEVEL: usize = 2; -/// Reputation -/// https://github.com/eth-infinitism/account-abstraction/blob/develop/eip/EIPS/eip-aa-rules.md#constants -pub mod reputation { - pub const MIN_UNSTAKE_DELAY: u64 = 86400; - // pub const MIN_STAKE_VALUE - Adjustable per chain value, Equivalent to ~$1000 in native tokens - pub const SAME_SENDER_MEMPOOL_COUNT: usize = 4; - pub const SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT: usize = 10; - pub const THROTTLED_ENTITY_MEMPOOL_COUNT: usize = 4; - pub const THROTTLED_ENTITY_LIVE_BLOCKS: usize = 4; - pub const THROTTLED_ENTITY_BUNDLE_COUNT: usize = 4; - pub const MIN_INCLUSION_RATE_DENOMINATOR: u64 = 10; - pub const INCLUSION_RATE_FACTOR: u64 = 10; - pub const THROTTLING_SLACK: u64 = 10; - pub const BAN_SLACK: u64 = 50; -} + pub const LEVEL_TO_ENTITY: [&str; NUMBER_OF_LEVELS] = [FACTORY, SENDER, PAYMASTER]; + } -/// User opereation mempool -pub mod uopool { - pub const GAS_INCREASE_PERC: u64 = 10; - pub const LATEST_SCAN_DEPTH: u64 = 1000; + /// Reputation + /// https://github.com/eth-infinitism/account-abstraction/blob/develop/eip/EIPS/eip-aa-rules.md#constants + pub mod reputation { + pub const MIN_UNSTAKE_DELAY: u64 = 86400; + // pub const MIN_STAKE_VALUE - Adjustable per chain value, Equivalent to ~$1000 in native + // tokens + pub const SAME_SENDER_MEMPOOL_COUNT: usize = 4; + pub const SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT: usize = 10; + pub const THROTTLED_ENTITY_MEMPOOL_COUNT: usize = 4; + pub const THROTTLED_ENTITY_LIVE_BLOCKS: usize = 4; + pub const THROTTLED_ENTITY_BUNDLE_COUNT: usize = 4; + pub const MIN_INCLUSION_RATE_DENOMINATOR: u64 = 10; + pub const INCLUSION_RATE_FACTOR: u64 = 10; + pub const THROTTLING_SLACK: u64 = 10; + pub const BAN_SLACK: u64 = 50; + } } -/// Builder JSON-RPC Endpoints +/// Flashbots relay endpoints pub mod flashbots_relay_endpoints { + // mainnet pub const FLASHBOTS: &str = "https://relay.flashbots.net"; - pub const FLASHBOTS_GOERLI: &str = "https://relay-goerli.flashbots.net"; pub const BUILDER0X69: &str = "http://builder0x69.io/"; pub const EDENNETWORK: &str = "https://api.edennetwork.io/v1/bundle"; pub const BEAVERBUILD: &str = "https://rpc.beaverbuild.org/"; @@ -71,10 +72,16 @@ pub mod flashbots_relay_endpoints { pub const RELAYOOR_WTF: &str = "https://relayooor.wtf/"; pub const RSYNC_BUILDER: &str = "https://rsync-builder.xyz/"; pub const LOKI_BUILDER: &str = "https://rpc.lokibuilder.xyz/"; + + // goerli + pub const FLASHBOTS_GOERLI: &str = "https://relay-goerli.flashbots.net"; } /// Supported chains pub mod supported_chains { + pub const SUPPORTED_CHAINS: [u64; 5] = [MAINNET, GOERLI, SEPOLIA, DEV, MUMBAI]; + pub const SUPPORTED_NAMED_CHAINS: [&str; 5] = ["mainnet", "goerli", "sepolia", "dev", "mumbai"]; + // dev pub const DEV: u64 = 1337; @@ -85,26 +92,47 @@ pub mod supported_chains { // polygon pub const MUMBAI: u64 = 80001; +} - pub const SUPPORTED_CHAINS: [u64; 5] = [MAINNET, GOERLI, SEPOLIA, DEV, MUMBAI]; - pub const SUPPORTED_NAMED_CHAINS: [&str; 5] = ["mainnet", "goerli", "sepolia", "dev", "mumbai"]; +/// RPC +pub mod rpc { + /// The default port for HTTP + pub const HTTP_PORT: u16 = 3000; + /// The default port for WS + pub const WS_PORT: u16 = 3001; + + pub const VALIDATION: i32 = -32500; + pub const PAYMASTER: i32 = -32501; + pub const OPCODE: i32 = -32502; + pub const EXPIRATION: i32 = -32503; + pub const ENTITY_BANNED_OR_THROTTLED: i32 = -32504; + pub const STAKE_TOO_LOW: i32 = -32505; + pub const SIGNATURE_AGGREGATOR: i32 = -32506; + pub const SIGNATURE: i32 = -32507; + pub const EXECUTION: i32 = -32521; + pub const USER_OPERATION_HASH: i32 = -32601; + pub const SANITY_CHECK: i32 = -32602; +} + +/// gRPC +pub mod grpc { + /// The default port for user operation mempool + pub const MEMPOOL_PORT: u16 = 3002; + /// The default port for bundler + pub const BUNDLER_PORT: u16 = 3003; } -/// Networking related constants -pub mod networking { - pub const DEFAULT_HTTP_RPC_PORT: u16 = 3000; - pub const DEFAULT_WS_RPC_PORT: u16 = 3001; - pub const DEFAULT_UOPOOL_GRPC_PORT: u16 = 3002; - pub const DEFAULT_BUNDLER_GRPC_PORT: u16 = 3003; +/// Storage +pub mod storage { + /// The default path for database + pub const DATABASE_FOLDER_NAME: &str = "db"; } -/// P2P related constants +/// P2P pub mod p2p { - /// The dafault database folder name used for storing the database files - pub const DB_FOLDER_NAME: &str = "db"; - /// The default node key file name used for storing the node p2p key + /// The default path for storing the node p2p key pub const NODE_KEY_FILE_NAME: &str = "p2p/node-key"; - /// The default node enr file name used for storing enr + /// The default path for storing the node enr pub const NODE_ENR_FILE_NAME: &str = "p2p/node-enr"; /// The prefix protocol id for request-response protocol pub const REQREP_PROTOCOL_PREFIX: &str = "/account_abstraction/req"; diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index e7a17b91..e34b431c 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -1,21 +1,23 @@ -#![allow(dead_code)] +//! Account abstraction (ERC-4337) primitive types +//! +//! This crate contains Account abstraction (ERC-4337) primitive types and helper functions. pub mod bundler; pub mod chain; -pub mod consts; +pub mod constants; +pub mod mempool; pub mod p2p; pub mod provider; pub mod reputation; pub mod sanity; pub mod simulation; -pub mod uopool; mod user_operation; mod utils; mod wallet; pub use bundler::Mode as BundlerMode; +pub use mempool::Mode as UoPoolMode; pub use p2p::{PooledUserOps, UserOperationsWithEntryPoint}; -pub use uopool::Mode as UoPoolMode; pub use user_operation::{ UserOperation, UserOperationByHash, UserOperationGasEstimation, UserOperationHash, UserOperationPartial, UserOperationReceipt, diff --git a/crates/primitives/src/uopool.rs b/crates/primitives/src/mempool.rs similarity index 97% rename from crates/primitives/src/uopool.rs rename to crates/primitives/src/mempool.rs index 9233e85b..bc99b57d 100644 --- a/crates/primitives/src/uopool.rs +++ b/crates/primitives/src/mempool.rs @@ -1,3 +1,5 @@ +//! Mempool/related primitives + use crate::{sanity::SanityCheckError, simulation::SimulationCheckError}; use serde::{Deserialize, Serialize}; use strum_macros::{EnumString, EnumVariantNames}; diff --git a/crates/primitives/src/p2p.rs b/crates/primitives/src/p2p.rs index 40f0bdba..2b14cd8f 100644 --- a/crates/primitives/src/p2p.rs +++ b/crates/primitives/src/p2p.rs @@ -1,9 +1,12 @@ +//! P2P primitives + use crate::UserOperation; use alloy_chains::Chain; use ethers::types::{Address, U256 as EthersU256}; use ssz_rs::{List, Vector, U256}; use ssz_rs_derive::Serializable; +/// Gossipsub message type #[derive(Clone, Debug, Default, Serializable, PartialEq)] pub struct UserOperationsWithEntryPoint { // entrypoint address @@ -50,6 +53,7 @@ impl UserOperationsWithEntryPoint { } } +/// Message type in Req/Resp protocol #[derive(Clone, Debug, Default, Serializable)] pub struct PooledUserOps { mempool_id: Vector, diff --git a/crates/primitives/src/provider.rs b/crates/primitives/src/provider.rs index 43d1714a..02956088 100644 --- a/crates/primitives/src/provider.rs +++ b/crates/primitives/src/provider.rs @@ -1,3 +1,5 @@ +//! Utils for creating ethers providers + use async_stream::stream; use ethers::{ providers::{Http, Middleware, Provider, Ws}, diff --git a/crates/primitives/src/reputation.rs b/crates/primitives/src/reputation.rs index ad64e932..6cadf9ea 100644 --- a/crates/primitives/src/reputation.rs +++ b/crates/primitives/src/reputation.rs @@ -1,3 +1,5 @@ +//! Primitives for reputation + use super::utils::{as_checksum_addr, as_hex_string, as_u64}; use educe::Educe; use ethers::{ @@ -67,12 +69,7 @@ pub struct ReputationEntry { impl ReputationEntry { pub fn default_with_addr(addr: Address) -> Self { - Self { - address: addr, - uo_seen: 0, - uo_included: 0, - status: Status::OK.into(), - } + Self { address: addr, uo_seen: 0, uo_included: 0, status: Status::OK.into() } } } diff --git a/crates/primitives/src/sanity.rs b/crates/primitives/src/sanity.rs index ff85e785..47cd10d5 100644 --- a/crates/primitives/src/sanity.rs +++ b/crates/primitives/src/sanity.rs @@ -1,3 +1,5 @@ +//! Sanity check (validation) primitives + use crate::reputation::ReputationError; use ethers::{ providers::MiddlewareError, @@ -8,59 +10,21 @@ use serde::{Deserialize, Serialize}; /// Error object for sanity check #[derive(Debug, Clone, Serialize, Deserialize)] pub enum SanityCheckError { - SenderOrInitCode { - sender: Address, - init_code: Bytes, - }, - FactoryVerification { - init_code: Bytes, - }, - HighVerificationGasLimit { - verification_gas_limit: U256, - max_verification_gas: U256, - }, - LowPreVerificationGas { - pre_verification_gas: U256, - pre_verification_gas_expected: U256, - }, - PaymasterVerification { - paymaster_and_data: Bytes, - }, - LowCallGasLimit { - call_gas_limit: U256, - call_gas_limit_expected: U256, - }, - LowMaxFeePerGas { - max_fee_per_gas: U256, - base_fee_per_gas: U256, - }, - HighMaxPriorityFeePerGas { - max_priority_fee_per_gas: U256, - max_fee_per_gas: U256, - }, - LowMaxPriorityFeePerGas { - max_priority_fee_per_gas: U256, - min_priority_fee_per_gas: U256, - }, - SenderVerification { - sender: Address, - message: String, - }, - EntityVerification { - entity: String, - address: Address, - message: String, - }, + SenderOrInitCode { sender: Address, init_code: Bytes }, + FactoryVerification { init_code: Bytes }, + HighVerificationGasLimit { verification_gas_limit: U256, max_verification_gas: U256 }, + LowPreVerificationGas { pre_verification_gas: U256, pre_verification_gas_expected: U256 }, + PaymasterVerification { paymaster_and_data: Bytes }, + LowCallGasLimit { call_gas_limit: U256, call_gas_limit_expected: U256 }, + LowMaxFeePerGas { max_fee_per_gas: U256, base_fee_per_gas: U256 }, + HighMaxPriorityFeePerGas { max_priority_fee_per_gas: U256, max_fee_per_gas: U256 }, + LowMaxPriorityFeePerGas { max_priority_fee_per_gas: U256, min_priority_fee_per_gas: U256 }, + SenderVerification { sender: Address, message: String }, + EntityVerification { entity: String, address: Address, message: String }, Reputation(ReputationError), - Validation { - message: String, - }, - MiddlewareError { - message: String, - }, - UnknownError { - message: String, - }, + Validation { message: String }, + MiddlewareError { message: String }, + UnknownError { message: String }, } impl From for SanityCheckError { @@ -71,8 +35,6 @@ impl From for SanityCheckError { impl From for SanityCheckError { fn from(err: M) -> Self { - SanityCheckError::MiddlewareError { - message: err.to_string(), - } + SanityCheckError::MiddlewareError { message: err.to_string() } } } diff --git a/crates/primitives/src/simulation.rs b/crates/primitives/src/simulation.rs index f5939367..e5fdc079 100644 --- a/crates/primitives/src/simulation.rs +++ b/crates/primitives/src/simulation.rs @@ -1,3 +1,5 @@ +//! Simulation (validation) primitives + use ethers::{ prelude::{EthAbiCodec, EthAbiType}, providers::MiddlewareError, @@ -43,48 +45,22 @@ lazy_static! { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum SimulationCheckError { Signature {}, - Expiration { - valid_after: U256, - valid_until: U256, - paymaster: Option
, - }, - Validation { - message: String, - }, - Opcode { - entity: String, - opcode: String, - }, - Execution { - message: String, - }, - StorageAccess { - slot: String, - }, - Unstaked { - entity: String, - message: String, - }, - CallStack { - message: String, - }, - CodeHashes { - message: String, - }, + Expiration { valid_after: U256, valid_until: U256, paymaster: Option
}, + Validation { message: String }, + Opcode { entity: String, opcode: String }, + Execution { message: String }, + StorageAccess { slot: String }, + Unstaked { entity: String, message: String }, + CallStack { message: String }, + CodeHashes { message: String }, OutOfGas {}, - MiddlewareError { - message: String, - }, - UnknownError { - message: String, - }, + MiddlewareError { message: String }, + UnknownError { message: String }, } impl From for SimulationCheckError { fn from(err: M) -> Self { - SimulationCheckError::MiddlewareError { - message: err.to_string(), - } + SimulationCheckError::MiddlewareError { message: err.to_string() } } } diff --git a/crates/primitives/src/user_operation.rs b/crates/primitives/src/user_operation.rs index 77752c84..e8c5cdc7 100644 --- a/crates/primitives/src/user_operation.rs +++ b/crates/primitives/src/user_operation.rs @@ -1,3 +1,5 @@ +//! Basic transaction type for account abstraction (ERC-4337) + use super::utils::{as_checksum_addr, as_checksum_bytes, get_address}; use ethers::{ abi::AbiEncode, @@ -9,9 +11,11 @@ use rustc_hex::FromHexError; use serde::{Deserialize, Serialize}; use ssz_rs::List; use std::{ops::Deref, slice::Windows, str::FromStr}; + /// This could be increased if we found bigger bytes, the propper value is not sure right now. const MAXIMUM_SSZ_BYTES_LENGTH: usize = 1024; -/// Transaction type for ERC-4337 account abstraction + +/// Transaction type for account abstraction (ERC-4337) #[derive( Clone, Debug, @@ -47,7 +51,8 @@ pub struct UserOperation { /// The amount of gas to allocate for the verification step pub verification_gas_limit: U256, - /// The amount of gas to pay bundler to compensate for the pre-verification execution and calldata + /// The amount of gas to pay bundler to compensate for the pre-verification execution and + /// calldata pub pre_verification_gas: U256, /// Maximum fee per gas (similar to EIP-1559) @@ -56,7 +61,8 @@ pub struct UserOperation { /// Maximum priority fee per gas (similar to EIP-1559) pub max_priority_fee_per_gas: U256, - /// Address of paymaster sponsoring the user operation, followed by extra data to send to the paymaster (can be empty) + /// Address of paymaster sponsoring the user operation, followed by extra data to send to the + /// paymaster (can be empty) pub paymaster_and_data: Bytes, /// Data passed to the account along with the nonce during the verification step @@ -467,12 +473,10 @@ fn ssz_unpack_bytes( encoding: &[u8], total_bytes_read: usize, ) -> Result<(Bytes, usize), ssz_rs::DeserializeError> { - let range = bytes_zone - .next() - .ok_or(ssz_rs::DeserializeError::AdditionalInput { - provided: encoding.len(), - expected: total_bytes_read, - })?; + let range = bytes_zone.next().ok_or(ssz_rs::DeserializeError::AdditionalInput { + provided: encoding.len(), + expected: total_bytes_read, + })?; let start = range[0]; let end = range[1]; let bytes_data = Bytes::from_iter(encoding[start..end].iter()); @@ -492,12 +496,10 @@ impl ssz_rs::Deserialize for UserOperation { let encoded_length = <[u8; 20] as ssz_rs::Serializable>::size_hint(); let end = start + encoded_length; let target = - encoding - .get(start..end) - .ok_or(ssz_rs::DeserializeError::ExpectedFurtherInput { - provided: encoding.len() - start, - expected: encoded_length, - })?; + encoding.get(start..end).ok_or(ssz_rs::DeserializeError::ExpectedFurtherInput { + provided: encoding.len() - start, + expected: encoded_length, + })?; let result = <[u8; 20] as ssz_rs::Deserialize>::deserialize(target)?; container.sender = Address::from_slice(&result); encoded_length @@ -648,9 +650,7 @@ mod tests { ]; assert_eq!( uos[0].hash( - &"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - .parse() - .unwrap(), + &"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".parse().unwrap(), &80_001.into() ), "0x95418c07086df02ff6bc9e8bdc150b380cb761beecc098630440bcec6e862702" @@ -660,9 +660,7 @@ mod tests { ); assert_eq!( uos[1].hash( - &"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - .parse() - .unwrap(), + &"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".parse().unwrap(), &80_001.into() ), "0x7c1b8c9df49a9e09ecef0f0fe6841d895850d29820f9a4b494097764085dcd7e" @@ -704,10 +702,7 @@ mod tests { assert_eq!(uo_decode.verification_gas_limit, uo.verification_gas_limit); assert_eq!(uo_decode.pre_verification_gas, uo.pre_verification_gas); assert_eq!(uo_decode.max_fee_per_gas, uo.max_fee_per_gas); - assert_eq!( - uo_decode.max_priority_fee_per_gas, - uo.max_priority_fee_per_gas - ); + assert_eq!(uo_decode.max_priority_fee_per_gas, uo.max_priority_fee_per_gas); assert_eq!(uo_decode.paymaster_and_data, uo.paymaster_and_data); assert_eq!(uo_decode.signature, uo.signature); } diff --git a/crates/primitives/src/utils.rs b/crates/primitives/src/utils.rs index e4ceec1e..ee936c5d 100644 --- a/crates/primitives/src/utils.rs +++ b/crates/primitives/src/utils.rs @@ -1,3 +1,5 @@ +//! Misc utils + use ethers::{ types::{Address, Bytes, U256}, utils::{hex, to_checksum}, diff --git a/crates/primitives/src/wallet.rs b/crates/primitives/src/wallet.rs index 0985fa57..7c2fd6bd 100644 --- a/crates/primitives/src/wallet.rs +++ b/crates/primitives/src/wallet.rs @@ -1,4 +1,5 @@ -//! A `Wallet` is a wrapper around an ethers wallet with an optional field for Flashbots bundle identifier +//! Wrapper around an ethers wallet with an optional field for Flashbots bundle identifier + use crate::UserOperation; use ethers::{ prelude::{k256::ecdsa::SigningKey, rand}, @@ -19,7 +20,8 @@ pub struct Wallet { impl Wallet { /// Builds a `Wallet` and construct using a randomly generated number - /// if `flashbots_key` is true, then a Flashbots key is also created, otherwise it is set to None + /// if `flashbots_key` is true, then a Flashbots key is also created, otherwise it is set to + /// None /// /// # Arguments /// * `path` - The path to the file where the mnemonic phrase will be written @@ -59,15 +61,13 @@ impl Wallet { flashbots_signer: Some(flashbots_wallet.with_chain_id(chain_id.as_u64())), }) } else { - Ok(Self { - signer: wallet.with_chain_id(chain_id.as_u64()), - flashbots_signer: None, - }) + Ok(Self { signer: wallet.with_chain_id(chain_id.as_u64()), flashbots_signer: None }) } } /// Create a new wallet from the given file containing the mnemonic phrase - /// if `flashbots_key` is true, then a Flashbots key is also created, otherwise it is set to None + /// if `flashbots_key` is true, then a Flashbots key is also created, otherwise it is set to + /// None /// /// # Arguments /// * `path` - The path to the file where the mnemonic phrase is stored @@ -100,15 +100,13 @@ impl Wallet { flashbots_signer: Some(flashbots_wallet.with_chain_id(chain_id.as_u64())), }) } else { - Ok(Self { - signer: wallet.with_chain_id(chain_id.as_u64()), - flashbots_signer: None, - }) + Ok(Self { signer: wallet.with_chain_id(chain_id.as_u64()), flashbots_signer: None }) } } /// Create a new wallet from the given mnemonic phrase - /// if `flashbots_key` is true, then a Flashbots key is also created, otherwise it is set to None + /// if `flashbots_key` is true, then a Flashbots key is also created, otherwise it is set to + /// None /// /// # Arguments /// * `phrase` - The mnemonic phrase @@ -136,10 +134,7 @@ impl Wallet { flashbots_signer: Some(flashbots_wallet.with_chain_id(chain_id.as_u64())), }) } else { - Ok(Self { - signer: wallet.with_chain_id(chain_id.as_u64()), - flashbots_signer: None, - }) + Ok(Self { signer: wallet.with_chain_id(chain_id.as_u64()), flashbots_signer: None }) } } @@ -160,9 +155,6 @@ impl Wallet { ) -> eyre::Result { let h = uo.hash(ep, chain_id); let sig = self.signer.sign_message(h.0.as_bytes()).await?; - Ok(UserOperation { - signature: sig.to_vec().into(), - ..uo.clone() - }) + Ok(UserOperation { signature: sig.to_vec().into(), ..uo.clone() }) } } diff --git a/crates/rpc/Cargo.toml b/crates/rpc/Cargo.toml index a467eec9..ff3204df 100644 --- a/crates/rpc/Cargo.toml +++ b/crates/rpc/Cargo.toml @@ -6,25 +6,38 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler RPC implementation -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-4337) RPC implementation" +homepage = "https://github.com/silius-rs/silius/tree/main/crates/rpc" [dependencies] -async-trait = { workspace = true } +# workspace dependencies +silius-grpc = { workspace = true } +silius-primitives = { workspace = true } + +# eth ethers = { workspace = true } -eyre = { workspace = true } -git-version = "0.3.5" + +# rpc hyper = { version = "0.14" } hyper-tls = { version = "0.5.0" } jsonrpsee = { version = "0.18.2", features = ["server", "macros", "client"] } -serde = "1" -serde_json = { workspace = true } -silius-grpc = { path = "../grpc" } -silius-primitives = { path = "../primitives" } -tonic = { version = "0.8", default-features = false, features = ["transport"] } tower = { version = "0.4.13" } tower-http = { version = "0.4.1", features = ["cors"] } +# grpc +tonic = { version = "0.8", default-features = false, features = ["transport"] } + +# async +async-trait = { workspace = true } + +# misc +eyre = { workspace = true } +git-version = "0.3.5" +serde = "1" +serde_json = { workspace = true } + [dev-dependencies] +# tokio tokio = { workspace = true, features = ["full"] } diff --git a/crates/rpc/README.md b/crates/rpc/README.md index f0546217..46db2eb7 100644 --- a/crates/rpc/README.md +++ b/crates/rpc/README.md @@ -1,4 +1,4 @@ -# Silius RPC +# silius-rpc Silius RPC crate provides an interface for handling RPC methods according to the [ERC-4337 specs](https://eips.ethereum.org/EIPS/eip-4337#rpc-methods-eth-namespace). diff --git a/crates/rpc/src/debug.rs b/crates/rpc/src/debug.rs index abc7a1b5..a0a39861 100644 --- a/crates/rpc/src/debug.rs +++ b/crates/rpc/src/debug.rs @@ -14,13 +14,14 @@ use silius_grpc::{ SetReputationResult, }; use silius_primitives::{ - bundler::DEFAULT_BUNDLE_INTERVAL, + constants::bundler::BUNDLE_INTERVAL, reputation::{ReputationEntry, StakeInfoResponse}, BundlerMode, UserOperation, }; use tonic::Request; -/// DebugApiServerImpl implements the ERC-4337 `debug` namespace rpc methods trait [DebugApiServer](DebugApiServer). +/// DebugApiServerImpl implements the ERC-4337 `debug` namespace rpc methods trait +/// [DebugApiServer](DebugApiServer). pub struct DebugApiServerImpl { pub uopool_grpc_client: UoPoolClient, pub bundler_grpc_client: BundlerClient, @@ -70,11 +71,7 @@ impl DebugApiServer for DebugApiServerImpl { async fn clear_state(&self) -> RpcResult { let mut uopool_grpc_client = self.uopool_grpc_client.clone(); - uopool_grpc_client - .clear(Request::new(())) - .await - .map_err(JsonRpcError::from)? - .into_inner(); + uopool_grpc_client.clear(Request::new(())).await.map_err(JsonRpcError::from)?.into_inner(); Ok(ResponseSuccess::Ok) } @@ -90,15 +87,9 @@ impl DebugApiServer for DebugApiServerImpl { async fn dump_mempool(&self, ep: Address) -> RpcResult> { let mut uopool_grpc_client = self.uopool_grpc_client.clone(); - let req = Request::new(GetAllRequest { - ep: Some(ep.into()), - }); + let req = Request::new(GetAllRequest { ep: Some(ep.into()) }); - let res = uopool_grpc_client - .get_all(req) - .await - .map_err(JsonRpcError::from)? - .into_inner(); + let res = uopool_grpc_client.get_all(req).await.map_err(JsonRpcError::from)?.into_inner(); let mut uos: Vec = res.uos.iter().map(|uo| uo.clone().into()).collect(); uos.sort_by(|a, b| a.nonce.cmp(&b.nonce)); @@ -106,10 +97,12 @@ impl DebugApiServer for DebugApiServerImpl { } /// Set the reputations for the given array of [ReputationEntry](ReputationEntry) - /// and send it to the UoPool gRPC service through the [SetReputationRequest](SetReputationRequest). + /// and send it to the UoPool gRPC service through the + /// [SetReputationRequest](SetReputationRequest). /// /// # Arguments - /// * `reputation_entries: Vec` - The [ReputationEntry](ReputationEntry) to be set. + /// * `reputation_entries: Vec` - The [ReputationEntry](ReputationEntry) to be + /// set. /// * `entry_point: Address` - The address of the entry point. /// /// # Returns @@ -126,11 +119,8 @@ impl DebugApiServer for DebugApiServerImpl { ep: Some(ep.into()), }); - let res = uopool_grpc_client - .set_reputation(req) - .await - .map_err(JsonRpcError::from)? - .into_inner(); + let res = + uopool_grpc_client.set_reputation(req).await.map_err(JsonRpcError::from)?.into_inner(); if res.res == SetReputationResult::SetReputation as i32 { return Ok(ResponseSuccess::Ok); @@ -143,7 +133,8 @@ impl DebugApiServer for DebugApiServerImpl { )) } - /// Return the all of [ReputationEntries](ReputationEntry) in the mempool via the [GetAllReputationRequest](GetAllReputationRequest). + /// Return the all of [ReputationEntries](ReputationEntry) in the mempool via the + /// [GetAllReputationRequest](GetAllReputationRequest). /// /// # Arguments /// * `entry_point: Address` - The address of the entry point. @@ -153,9 +144,7 @@ impl DebugApiServer for DebugApiServerImpl { async fn dump_reputation(&self, ep: Address) -> RpcResult> { let mut uopool_grpc_client = self.uopool_grpc_client.clone(); - let request = Request::new(GetAllReputationRequest { - ep: Some(ep.into()), - }); + let request = Request::new(GetAllReputationRequest { ep: Some(ep.into()) }); let res = uopool_grpc_client .get_all_reputation(request) @@ -178,7 +167,7 @@ impl DebugApiServer for DebugApiServerImpl { let req = Request::new(SetModeRequest { mode: Into::::into(mode).into(), - interval: DEFAULT_BUNDLE_INTERVAL, + interval: BUNDLE_INTERVAL, }); match bundler_grpc_client.set_bundler_mode(req).await { @@ -188,7 +177,8 @@ impl DebugApiServer for DebugApiServerImpl { } /// Immediately send the current bundle of user operations. - /// This is useful for testing or in situations where waiting for the next scheduled bundle is not desirable. + /// This is useful for testing or in situations where waiting for the next scheduled bundle is + /// not desirable. /// /// /// # Returns @@ -199,11 +189,7 @@ impl DebugApiServer for DebugApiServerImpl { let req = Request::new(()); match bundler_grpc_client.send_bundle_now(req).await { - Ok(res) => Ok(res - .into_inner() - .res - .expect("Must return send bundle tx data") - .into()), + Ok(res) => Ok(res.into_inner().res.expect("Must return send bundle tx data").into()), Err(s) => Err(JsonRpcError::from(s).into()), } } @@ -219,10 +205,8 @@ impl DebugApiServer for DebugApiServerImpl { async fn get_stake_status(&self, addr: Address, ep: Address) -> RpcResult { let mut uopool_grpc_client = self.uopool_grpc_client.clone(); - let req = Request::new(GetStakeInfoRequest { - addr: Some(addr.into()), - ep: Some(ep.into()), - }); + let req = + Request::new(GetStakeInfoRequest { addr: Some(addr.into()), ep: Some(ep.into()) }); match uopool_grpc_client.get_stake_info(req).await { Ok(res) => Ok({ diff --git a/crates/rpc/src/debug_api.rs b/crates/rpc/src/debug_api.rs index 7993e9ac..fc1e6155 100644 --- a/crates/rpc/src/debug_api.rs +++ b/crates/rpc/src/debug_api.rs @@ -53,7 +53,8 @@ pub trait DebugApi { /// Set the reputations for the given array of [ReputationEntry](ReputationEntry) /// /// # Arguments - /// * `reputation_entries: Vec` - The [ReputationEntry](ReputationEntry) to be set. + /// * `reputation_entries: Vec` - The [ReputationEntry](ReputationEntry) to be + /// set. /// * `entry_point: Address` - The address of the entry point. /// /// # Returns @@ -86,7 +87,8 @@ pub trait DebugApi { async fn set_bundling_mode(&self, mode: BundlerMode) -> RpcResult; /// Immediately send the current bundle of user operations. - /// This is useful for testing or in situations where waiting for the next scheduled bundle is not desirable. + /// This is useful for testing or in situations where waiting for the next scheduled bundle is + /// not desirable. /// /// /// # Returns diff --git a/crates/rpc/src/error.rs b/crates/rpc/src/error.rs index 7ff7035e..f8daae2e 100644 --- a/crates/rpc/src/error.rs +++ b/crates/rpc/src/error.rs @@ -1,14 +1,14 @@ use jsonrpsee::types::{error::ErrorCode, ErrorObject, ErrorObjectOwned}; use serde_json::json; use silius_primitives::{ - consts::rpc_error_codes::{ + constants::rpc::{ ENTITY_BANNED_OR_THROTTLED, EXECUTION, EXPIRATION, OPCODE, SANITY_CHECK, SIGNATURE, STAKE_TOO_LOW, VALIDATION, }, + mempool::ValidationError, reputation::ReputationError, sanity::SanityCheckError, simulation::SimulationCheckError, - uopool::ValidationError, }; /// A wrapper for the [ErrorObjectOwned](ErrorObjectOwned) type. @@ -202,14 +202,8 @@ impl From for JsonRpcError { "Invalid UserOp signature or paymaster signature", None::, ), - SimulationCheckError::Expiration { - valid_after, - valid_until, - paymaster, - } => ErrorObject::owned( - EXPIRATION, - "User operation is expired or will expire soon", - { + SimulationCheckError::Expiration { valid_after, valid_until, paymaster } => { + ErrorObject::owned(EXPIRATION, "User operation is expired or will expire soon", { if let Some(paymaster) = paymaster { Some(json!({ "valid_after": valid_after, "valid_until": valid_until, "paymaster": paymaster, @@ -219,8 +213,8 @@ impl From for JsonRpcError { "valid_after": valid_after, "valid_until": valid_until, })) } - }, - ), + }) + } SimulationCheckError::Validation { message } => { ErrorObject::owned(VALIDATION, message, None::) } diff --git a/crates/rpc/src/eth.rs b/crates/rpc/src/eth.rs index 56ba4a88..0cbd28e1 100644 --- a/crates/rpc/src/eth.rs +++ b/crates/rpc/src/eth.rs @@ -10,14 +10,15 @@ use silius_grpc::{ EstimateUserOperationGasResult, UserOperationHashRequest, }; use silius_primitives::{ - consts::rpc_error_codes::USER_OPERATION_HASH, simulation::SimulationCheckError, - uopool::ValidationError, UserOperation, UserOperationByHash, UserOperationGasEstimation, - UserOperationHash, UserOperationPartial, UserOperationReceipt, + constants::rpc::USER_OPERATION_HASH, mempool::ValidationError, + simulation::SimulationCheckError, UserOperation, UserOperationByHash, + UserOperationGasEstimation, UserOperationHash, UserOperationPartial, UserOperationReceipt, }; use std::str::FromStr; use tonic::Request; -/// EthApiServer implements the ERC-4337 `eth` namespace RPC methods trait [EthApiServer](EthApiServer). +/// EthApiServer implements the ERC-4337 `eth` namespace RPC methods trait +/// [EthApiServer](EthApiServer). pub struct EthApiServerImpl { /// The [UoPool gRPC client](UoPoolClient). pub uopool_grpc_client: UoPoolClient, @@ -54,11 +55,7 @@ impl EthApiServer for EthApiServerImpl { .map_err(JsonRpcError::from)? .into_inner(); - return Ok(res - .eps - .into_iter() - .map(|ep| to_checksum(&ep.into(), None)) - .collect()); + return Ok(res.eps.into_iter().map(|ep| to_checksum(&ep.into(), None)).collect()); } /// Send a user operation via the [AddRequest](AddRequest). @@ -76,16 +73,9 @@ impl EthApiServer for EthApiServerImpl { ) -> RpcResult { let mut uopool_grpc_client = self.uopool_grpc_client.clone(); - let req = Request::new(AddRequest { - uo: Some(uo.into()), - ep: Some(ep.into()), - }); + let req = Request::new(AddRequest { uo: Some(uo.into()), ep: Some(ep.into()) }); - let res = uopool_grpc_client - .add(req) - .await - .map_err(JsonRpcError::from)? - .into_inner(); + let res = uopool_grpc_client.add(req).await.map_err(JsonRpcError::from)?.into_inner(); if res.res == AddResult::Added as i32 { let uo_hash = @@ -99,16 +89,18 @@ impl EthApiServer for EthApiServerImpl { .0) } - /// Estimate the gas required for a [UserOperation](UserOperation) via the [EstimateUserOperationGasRequest](EstimateUserOperationGasRequest). - /// This allows you to gauge the computational cost of the operation. - /// See [How ERC-4337 Gas Estimation Works](https://www.alchemy.com/blog/erc-4337-gas-estimation). + /// Estimate the gas required for a [UserOperation](UserOperation) via the + /// [EstimateUserOperationGasRequest](EstimateUserOperationGasRequest). This allows you to + /// gauge the computational cost of the operation. See [How ERC-4337 Gas Estimation Works](https://www.alchemy.com/blog/erc-4337-gas-estimation). /// /// # Arguments - /// * `user_operation: [UserOperationPartial](UserOperationPartial)` - The partial user operation for which to estimate the gas. + /// * `user_operation: [UserOperationPartial](UserOperationPartial)` - The partial user + /// operation for which to estimate the gas. /// * `entry_point: Address` - The address of the entry point. /// /// # Returns - /// * `RpcResult` - The [UserOperationGasEstimation](UserOperationGasEstimation) for the user operation. + /// * `RpcResult` - The + /// [UserOperationGasEstimation](UserOperationGasEstimation) for the user operation. async fn estimate_user_operation_gas( &self, uo: UserOperationPartial, @@ -145,23 +137,17 @@ impl EthApiServer for EthApiServerImpl { /// * `user_operation_hash: String` - The hash of the user operation. /// /// # Returns - /// * `RpcResult>` - The [UserOperationReceipt] of the user operation. + /// * `RpcResult>` - The [UserOperationReceipt] of the user + /// operation. async fn get_user_operation_receipt( &self, uo_hash: String, ) -> RpcResult> { match UserOperationHash::from_str(&uo_hash) { Ok(uo_hash) => { - let req = Request::new(UserOperationHashRequest { - hash: Some(uo_hash.into()), - }); + let req = Request::new(UserOperationHashRequest { hash: Some(uo_hash.into()) }); - match self - .uopool_grpc_client - .clone() - .get_user_operation_receipt(req) - .await - { + match self.uopool_grpc_client.clone().get_user_operation_receipt(req).await { Ok(res) => { let res = res.into_inner(); @@ -199,30 +185,25 @@ impl EthApiServer for EthApiServerImpl { } } - /// Retrieve a [UserOperation](UserOperation) by its hash via [UserOperationHashRequest](UserOperationHashRequest). - /// The hash serves as a unique identifier for the [UserOperation](UserOperation). + /// Retrieve a [UserOperation](UserOperation) by its hash via + /// [UserOperationHashRequest](UserOperationHashRequest). The hash serves as a unique + /// identifier for the [UserOperation](UserOperation). /// /// # Arguments /// * `user_operation_hash: String` - The hash of a [UserOperation](UserOperation). /// /// # Returns - /// * `RpcResult>` - The [UserOperation](UserOperation) associated with the hash, or None if it does not exist. + /// * `RpcResult>` - The [UserOperation](UserOperation) associated + /// with the hash, or None if it does not exist. async fn get_user_operation_by_hash( &self, uo_hash: String, ) -> RpcResult> { match UserOperationHash::from_str(&uo_hash) { Ok(uo_hash) => { - let req = Request::new(UserOperationHashRequest { - hash: Some(uo_hash.into()), - }); + let req = Request::new(UserOperationHashRequest { hash: Some(uo_hash.into()) }); - match self - .uopool_grpc_client - .clone() - .get_user_operation_by_hash(req) - .await - { + match self.uopool_grpc_client.clone().get_user_operation_by_hash(req).await { Ok(res) => { let res = res.into_inner(); diff --git a/crates/rpc/src/eth_api.rs b/crates/rpc/src/eth_api.rs index eac97bd6..03862251 100644 --- a/crates/rpc/src/eth_api.rs +++ b/crates/rpc/src/eth_api.rs @@ -44,11 +44,13 @@ pub trait EthApi { /// See [How ERC-4337 Gas Estimation Works](https://www.alchemy.com/blog/erc-4337-gas-estimation). /// /// # Arguments - /// * `user_operation: [UserOperationPartial](UserOperationPartial)` - A [partial user operation](UserOperationPartial) for which to estimate the gas. + /// * `user_operation: [UserOperationPartial](UserOperationPartial)` - A [partial user + /// operation](UserOperationPartial) for which to estimate the gas. /// * `entry_point: Address` - The address of the entry point. /// /// # Returns - /// * `RpcResult` - The estimated gas for the [UserOperation](UserOperation) + /// * `RpcResult` - The estimated gas for the + /// [UserOperation](UserOperation) #[method(name = "estimateUserOperationGas")] async fn estimate_user_operation_gas( &self, @@ -63,7 +65,8 @@ pub trait EthApi { /// * `user_operation_hash: String` - The hash of a [UserOperation](UserOperation). /// /// # Returns - /// * `RpcResult>` - The receipt of the [UserOperation](UserOperation), or None if it does not exist. + /// * `RpcResult>` - The receipt of the + /// [UserOperation](UserOperation), or None if it does not exist. #[method(name = "getUserOperationReceipt")] async fn get_user_operation_receipt( &self, @@ -77,7 +80,8 @@ pub trait EthApi { /// * `user_operation_hash: String` - The hash of the user operation. /// /// # Returns - /// * `RpcResult>` - The [UserOperation](UserOperation) associated with the hash, or None if it does not exist. + /// * `RpcResult>` - The [UserOperation](UserOperation) associated + /// with the hash, or None if it does not exist. #[method(name = "getUserOperationByHash")] async fn get_user_operation_by_hash( &self, diff --git a/crates/rpc/src/middleware.rs b/crates/rpc/src/middleware.rs index 75dda047..b5df02e1 100644 --- a/crates/rpc/src/middleware.rs +++ b/crates/rpc/src/middleware.rs @@ -1,13 +1,19 @@ use hyper::{Body, Request, Response}; use hyper_tls::HttpsConnector; -use jsonrpsee::core::error::Error as JsonRpcError; -use jsonrpsee::types::error::{ErrorCode, METHOD_NOT_FOUND_MSG}; -use jsonrpsee::types::ErrorObjectOwned; -use std::future::Future; -use std::pin::Pin; -use std::sync::Arc; -use std::task::Poll; -use std::{error::Error, task::Context}; +use jsonrpsee::{ + core::error::Error as JsonRpcError, + types::{ + error::{ErrorCode, METHOD_NOT_FOUND_MSG}, + ErrorObjectOwned, + }, +}; +use std::{ + error::Error, + future::Future, + pin::Pin, + sync::Arc, + task::{Context, Poll}, +}; use tower::{Layer, Service}; /// The proxy layer for the [json rpc server](JsonRpcServer) @@ -26,9 +32,7 @@ impl ProxyJsonRpcLayer { /// # Returns /// * `Self` - A ProxyJsonRpcLayer instance pub fn new(address: impl Into) -> Self { - Self { - address: address.into(), - } + Self { address: address.into() } } } @@ -60,10 +64,7 @@ impl ProxyJsonRpcRequest { /// # Returns /// * `Result` - A ProxyJsonRpcRequest instance pub fn new(inner: S, address: &str) -> Result { - Ok(Self { - inner, - address: Arc::from(address), - }) + Ok(Self { inner, address: Arc::from(address) }) } } @@ -104,8 +105,8 @@ where } if let Ok(err) = serde_json::from_slice::(&res_bb) { - if err.error.code() == ErrorCode::MethodNotFound.code() - && err.error.message() == METHOD_NOT_FOUND_MSG + if err.error.code() == ErrorCode::MethodNotFound.code() && + err.error.message() == METHOD_NOT_FOUND_MSG { let req = Request::post(addr.clone()) .header(hyper::header::CONTENT_TYPE, "application/json") diff --git a/crates/rpc/src/rpc.rs b/crates/rpc/src/rpc.rs index 90f90a53..859534b6 100644 --- a/crates/rpc/src/rpc.rs +++ b/crates/rpc/src/rpc.rs @@ -90,10 +90,7 @@ impl JsonRpcServer { /// * `Self` - A new [JsonRpcServer](JsonRpcServer) instance. pub fn with_cors(mut self, cors_domain: &[String], typ: JsonRpcServerType) -> Self { let cors_layer = if cors_domain.iter().any(|d| d == "*") { - CorsLayer::new() - .allow_headers(Any) - .allow_methods([Method::POST]) - .allow_origin(Any) + CorsLayer::new().allow_headers(Any).allow_methods([Method::POST]).allow_origin(Any) } else { let mut origins: Vec = vec![]; @@ -161,7 +158,8 @@ impl JsonRpcServer { /// Start the [json RPC server](JsonRpcServer) /// /// # Returns - /// * `Result<(Option, Option), Error>` - The [handle]((Option, Option)) of the HTTP and WS servers. + /// * `Result<(Option, Option), Error>` - The + /// [handle]((Option, Option)) of the HTTP and WS servers. pub async fn start(&self) -> eyre::Result<(Option, Option)> { let http_handle = if self.http { let service = ServiceBuilder::new() diff --git a/crates/rpc/src/web3.rs b/crates/rpc/src/web3.rs index 64dc32b5..391cbae5 100644 --- a/crates/rpc/src/web3.rs +++ b/crates/rpc/src/web3.rs @@ -1,7 +1,7 @@ use crate::web3_api::Web3ApiServer; use async_trait::async_trait; use jsonrpsee::core::RpcResult; -use silius_primitives::consts::entry_point::VERSION; +use silius_primitives::constants::entry_point::VERSION; pub struct Web3ApiServerImpl {} diff --git a/crates/rpc/tests/common.rs b/crates/rpc/tests/common.rs index 72e18c3d..9612de4e 100644 --- a/crates/rpc/tests/common.rs +++ b/crates/rpc/tests/common.rs @@ -1,13 +1,15 @@ use async_trait::async_trait; use ethers::types::U64; -use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; -use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use jsonrpsee::{ core::{Error as RpcError, RpcResult}, + http_client::{HttpClient, HttpClientBuilder}, proc_macros::rpc, + ws_client::{WsClient, WsClientBuilder}, +}; +use std::{ + net::{IpAddr, Ipv4Addr}, + sync::atomic::{AtomicU16, Ordering}, }; -use std::net::{IpAddr, Ipv4Addr}; -use std::sync::atomic::{AtomicU16, Ordering}; pub static ADDRESS: Ipv4Addr = Ipv4Addr::UNSPECIFIED; static PORT: AtomicU16 = AtomicU16::new(8000); @@ -45,7 +47,5 @@ pub fn build_http_client(addr: IpAddr, port: u16) -> Result Result { - WsClientBuilder::default() - .build(format!("ws://{}:{}", addr, port)) - .await + WsClientBuilder::default().build(format!("ws://{}:{}", addr, port)).await } diff --git a/crates/rpc/tests/rpc.rs b/crates/rpc/tests/rpc.rs index 44d39c73..175f963a 100644 --- a/crates/rpc/tests/rpc.rs +++ b/crates/rpc/tests/rpc.rs @@ -20,10 +20,7 @@ async fn only_http_rpc_server() { let chain_id: U64 = U64::from(0x7a69); server - .add_methods( - DummyEthApiServerImpl { chain_id }.into_rpc(), - JsonRpcServerType::Http, - ) + .add_methods(DummyEthApiServerImpl { chain_id }.into_rpc(), JsonRpcServerType::Http) .unwrap(); let (http_handle, _ws_handle) = server.start().await.unwrap(); @@ -48,10 +45,7 @@ async fn only_ws_rpc_server() { let chain_id: U64 = U64::from(0x7a69); server - .add_methods( - DummyEthApiServerImpl { chain_id }.into_rpc(), - JsonRpcServerType::Ws, - ) + .add_methods(DummyEthApiServerImpl { chain_id }.into_rpc(), JsonRpcServerType::Ws) .unwrap(); let (_http_handle, ws_handle) = server.start().await.unwrap(); @@ -79,10 +73,7 @@ async fn http_and_ws_rpc_server() { let chain_id: U64 = U64::from(0x7a69); server - .add_methods( - DummyEthApiServerImpl { chain_id }.into_rpc(), - JsonRpcServerType::Both, - ) + .add_methods(DummyEthApiServerImpl { chain_id }.into_rpc(), JsonRpcServerType::Both) .unwrap(); let (http_handle, ws_handle) = server.start().await.unwrap(); diff --git a/docker-compose.yml b/docker-compose.yml index f3c152b8..b7d98c98 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: network_mode: host volumes: - ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266:/data/silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 - - ./db:/data/silius/db + - ./.local/db:/data/silius/db - ./bundler-spec-tests/p2p:/data/silius/p2p command: - node diff --git a/examples/simple-account/Cargo.toml b/examples/simple-account/Cargo.toml index 472b0e98..aa92f767 100644 --- a/examples/simple-account/Cargo.toml +++ b/examples/simple-account/Cargo.toml @@ -6,22 +6,32 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler examples - simple account -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-433) examples - simple account" +homepage = "https://github.com/silius-rs/silius/tree/main/examples/simple-account" [dependencies] +# silius dependencies +silius-contracts = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" +silius-primitives = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" +silius-tests = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" + +# eth alloy-primitives = "0.3" alloy-sol-types = "0.3" ethers = { workspace = true } -eyre = { workspace = true } + +# rpc reqwest = { version = "0.11.4", features = ["json"] } + +# tokio +tokio = { workspace = true } + +# misc +eyre = { workspace = true } serde = "1" serde_json = "1" -silius-contracts = { path = "../../crates/contracts" } -silius-primitives = { path = "../../crates/primitives" } -silius-tests = { path = "../../tests" } -tokio = { workspace = true } [package.metadata.cargo-udeps.ignore] normal = ["silius-contracts", "silius-primitives", "silius-tests"] diff --git a/examples/simple-account/examples/create.rs b/examples/simple-account/examples/create.rs index f28b792e..ff282879 100644 --- a/examples/simple-account/examples/create.rs +++ b/examples/simple-account/examples/create.rs @@ -8,9 +8,7 @@ use examples_simple_account::{ simple_account::SimpleAccountExecute, EstimateResult, Request, Response, }; use reqwest; -use silius_primitives::consts::entry_point::ADDRESS; -use silius_primitives::UserOperation; -use silius_primitives::Wallet as UoWallet; +use silius_primitives::{constants::entry_point::ADDRESS, UserOperation, Wallet as UoWallet}; use silius_tests::common::gen::SimpleAccountFactory; use std::{env, sync::Arc, time::Duration}; @@ -27,9 +25,7 @@ async fn main() -> eyre::Result<()> { .interval(Duration::from_millis(10u64)); let chain_id = provider.get_chainid().await?.as_u64(); - let wallet = MnemonicBuilder::::default() - .phrase(seed_phrase.as_str()) - .build()?; + let wallet = MnemonicBuilder::::default().phrase(seed_phrase.as_str()).build()?; let client = SignerMiddleware::new(provider.clone(), wallet.clone().with_chain_id(chain_id)) .nonce_manager(wallet.address()); @@ -59,10 +55,7 @@ async fn main() -> eyre::Result<()> { println!("init_code: {:?}", init_code); let (gas_price, priority_fee) = provider.estimate_eip1559_fees(None).await?; - println!( - "gas_price: {:?}, priority_fee: {:?}", - gas_price, priority_fee - ); + println!("gas_price: {:?}, priority_fee: {:?}", gas_price, priority_fee); let execution = SimpleAccountExecute::new(Address::zero(), U256::from(0), Bytes::default()); println!("{:}", Bytes::from(execution.encode())); @@ -81,11 +74,7 @@ async fn main() -> eyre::Result<()> { }; let uo_wallet = UoWallet::from_phrase(seed_phrase.as_str(), &chain_id.into(), false)?; let user_op = uo_wallet - .sign_uo( - &user_op, - &ADDRESS.to_string().parse::
()?, - &chain_id.into(), - ) + .sign_uo(&user_op, &ADDRESS.to_string().parse::
()?, &chain_id.into()) .await?; let value = serde_json::to_value(&user_op).unwrap(); @@ -110,10 +99,7 @@ async fn main() -> eyre::Result<()> { println!("json: {:?}", v); let user_op = UserOperation { - pre_verification_gas: v - .result - .pre_verification_gas - .saturating_add(U256::from(1000)), + pre_verification_gas: v.result.pre_verification_gas.saturating_add(U256::from(1000)), verification_gas_limit: v.result.verification_gas_limit, call_gas_limit: v.result.call_gas_limit.saturating_add(U256::from(2000)), max_priority_fee_per_gas: priority_fee, @@ -121,21 +107,14 @@ async fn main() -> eyre::Result<()> { ..user_op }; let user_op = uo_wallet - .sign_uo( - &user_op, - &ADDRESS.to_string().parse::
()?, - &chain_id.into(), - ) + .sign_uo(&user_op, &ADDRESS.to_string().parse::
()?, &chain_id.into()) .await?; let send_body = Request { jsonrpc: "2.0".to_string(), id: 1, method: "eth_sendUserOperation".to_string(), - params: vec![ - serde_json::to_value(&user_op).unwrap(), - ADDRESS.to_string().into(), - ], + params: vec![serde_json::to_value(&user_op).unwrap(), ADDRESS.to_string().into()], }; let post = reqwest::Client::builder() .build()? diff --git a/examples/simple-account/examples/deposit.rs b/examples/simple-account/examples/deposit.rs index 1d998a98..7c06dde5 100644 --- a/examples/simple-account/examples/deposit.rs +++ b/examples/simple-account/examples/deposit.rs @@ -6,7 +6,7 @@ use ethers::{ utils::parse_ether, }; use silius_contracts::entry_point::EntryPointAPI; -use silius_primitives::consts::entry_point::ADDRESS; +use silius_primitives::constants::entry_point::ADDRESS; use silius_tests::common::gen::SimpleAccountFactory; use std::{env, sync::Arc, time::Duration}; @@ -24,9 +24,7 @@ async fn main() -> eyre::Result<()> { Provider::::try_from(provider_url)?.interval(Duration::from_millis(10u64)); let chain_id = provider.get_chainid().await?.as_u64(); - let wallet = MnemonicBuilder::::default() - .phrase(seed_phrase.as_str()) - .build()?; + let wallet = MnemonicBuilder::::default().phrase(seed_phrase.as_str()).build()?; let client = SignerMiddleware::new(provider.clone(), wallet.clone().with_chain_id(chain_id)) .nonce_manager(wallet.address()) diff --git a/examples/simple-account/examples/transfer.rs b/examples/simple-account/examples/transfer.rs index 376a0ee7..922e082c 100644 --- a/examples/simple-account/examples/transfer.rs +++ b/examples/simple-account/examples/transfer.rs @@ -10,9 +10,7 @@ use examples_simple_account::{ }; use reqwest; use silius_contracts::EntryPoint; -use silius_primitives::consts::entry_point::ADDRESS; -use silius_primitives::UserOperation; -use silius_primitives::Wallet as UoWallet; +use silius_primitives::{constants::entry_point::ADDRESS, UserOperation, Wallet as UoWallet}; use silius_tests::common::gen::SimpleAccountFactory; use std::{env, sync::Arc, time::Duration}; @@ -31,9 +29,7 @@ async fn main() -> eyre::Result<()> { .interval(Duration::from_millis(10u64)); let chain_id = provider.get_chainid().await?.as_u64(); - let wallet = MnemonicBuilder::::default() - .phrase(seed_phrase.as_str()) - .build()?; + let wallet = MnemonicBuilder::::default().phrase(seed_phrase.as_str()).build()?; let client = SignerMiddleware::new(provider.clone(), wallet.clone().with_chain_id(chain_id)) .nonce_manager(wallet.address()); @@ -58,10 +54,7 @@ async fn main() -> eyre::Result<()> { .await?; println!("nonce: {:?}", nonce); let (gas_price, priority_fee) = provider.estimate_eip1559_fees(None).await?; - println!( - "gas_price: {:?}, priority_fee: {:?}", - gas_price, priority_fee - ); + println!("gas_price: {:?}, priority_fee: {:?}", gas_price, priority_fee); let execution = SimpleAccountExecute::new(address, parse_ether(TRANSFER_VALUE)?, Bytes::default()); @@ -81,11 +74,7 @@ async fn main() -> eyre::Result<()> { }; let uo_wallet = UoWallet::from_phrase(seed_phrase.as_str(), &chain_id.into(), false)?; let user_op = uo_wallet - .sign_uo( - &user_op, - &ADDRESS.to_string().parse::
()?, - &chain_id.into(), - ) + .sign_uo(&user_op, &ADDRESS.to_string().parse::
()?, &chain_id.into()) .await?; let value = serde_json::to_value(&user_op).unwrap(); @@ -110,42 +99,25 @@ async fn main() -> eyre::Result<()> { println!("json: {:?}", v); let user_op = UserOperation { - pre_verification_gas: v - .result - .pre_verification_gas - .saturating_add(U256::from(1000)), - verification_gas_limit: v - .result - .verification_gas_limit - .saturating_mul(U256::from(2)), + pre_verification_gas: v.result.pre_verification_gas.saturating_add(U256::from(1000)), + verification_gas_limit: v.result.verification_gas_limit.saturating_mul(U256::from(2)), call_gas_limit: v.result.call_gas_limit.saturating_mul(U256::from(2)), max_priority_fee_per_gas: priority_fee, max_fee_per_gas: gas_price, ..user_op }; let user_op = uo_wallet - .sign_uo( - &user_op, - &ADDRESS.to_string().parse::
()?, - &chain_id.into(), - ) + .sign_uo(&user_op, &ADDRESS.to_string().parse::
()?, &chain_id.into()) .await?; let send_body = Request { jsonrpc: "2.0".to_string(), id: 1, method: "eth_sendUserOperation".to_string(), - params: vec![ - serde_json::to_value(&user_op).unwrap(), - ADDRESS.to_string().into(), - ], + params: vec![serde_json::to_value(&user_op).unwrap(), ADDRESS.to_string().into()], }; - let post = reqwest::Client::builder() - .build()? - .post(bundler_url) - .json(&send_body) - .send() - .await?; + let post = + reqwest::Client::builder().build()?.post(bundler_url).json(&send_body).send().await?; println!("post: {:?}", post); let res = post.text().await?; diff --git a/examples/storage/Cargo.toml b/examples/storage/Cargo.toml index 6fbb18a1..119298ca 100644 --- a/examples/storage/Cargo.toml +++ b/examples/storage/Cargo.toml @@ -6,22 +6,32 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler examples - storage -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-433) examples - storage options" +homepage = "https://github.com/silius-rs/silius/tree/main/examples/storage" [dependencies] +# silius dependencies +silius-contracts = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" +silius-mempool = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" +silius-primitives = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" + +# eth alloy-chains = { workspace = true } ethers = { workspace = true } -eyre = { workspace = true } + +# async futures = "0.3.28" parking_lot = { workspace = true } -silius-contracts = { path = "../../crates/contracts" } -silius-primitives = { path = "../../crates/primitives" } -silius-uopool = { path = "../../crates/uopool" } -tempdir = "0.3.7" + +# tokio tokio = { workspace = true } +# misc +eyre = { workspace = true } +tempdir = "0.3.7" + [[example]] name = "memory" path = "examples/memory.rs" @@ -29,4 +39,3 @@ path = "examples/memory.rs" [[example]] name = "database" path = "examples/database.rs" - diff --git a/examples/storage/examples/database.rs b/examples/storage/examples/database.rs index 75ffdd35..a1eddfb6 100644 --- a/examples/storage/examples/database.rs +++ b/examples/storage/examples/database.rs @@ -2,20 +2,20 @@ use alloy_chains::Chain; use ethers::types::{Address, U256}; use parking_lot::RwLock; use silius_contracts::EntryPoint; +use silius_mempool::{ + init_env, validate::validator::new_canonical, CodeHashes, DatabaseTable, Mempool, Reputation, + UoPoolBuilder, UserOperations, UserOperationsByEntity, UserOperationsBySender, WriteMap, +}; use silius_primitives::{ - consts::{ + constants::{ entry_point::ADDRESS, - reputation::{ + validation::reputation::{ BAN_SLACK, MIN_INCLUSION_RATE_DENOMINATOR, MIN_UNSTAKE_DELAY, THROTTLING_SLACK, }, }, provider::create_http_provider, reputation::ReputationEntry, }; -use silius_uopool::{ - init_env, validate::validator::new_canonical, CodeHashes, DatabaseTable, Mempool, Reputation, - UoPoolBuilder, UserOperations, UserOperationsByEntity, UserOperationsBySender, WriteMap, -}; use std::{ collections::{HashMap, HashSet}, env, @@ -31,8 +31,7 @@ async fn main() -> eyre::Result<()> { // initialize database env let dir = TempDir::new("silius-db").unwrap(); let env = Arc::new(init_env::(dir.into_path()).expect("Init mdbx failed")); - env.create_tables() - .expect("Create mdbx database tables failed"); + env.create_tables().expect("Create mdbx database tables failed"); println!("Database uopool created!"); let provider = Arc::new(create_http_provider(provider_url.as_str()).await?); diff --git a/examples/storage/examples/memory.rs b/examples/storage/examples/memory.rs index 3f3ed899..a4dd7845 100644 --- a/examples/storage/examples/memory.rs +++ b/examples/storage/examples/memory.rs @@ -2,10 +2,11 @@ use alloy_chains::Chain; use ethers::types::{Address, U256}; use parking_lot::RwLock; use silius_contracts::EntryPoint; +use silius_mempool::{validate::validator::new_canonical, Mempool, Reputation, UoPoolBuilder}; use silius_primitives::{ - consts::{ + constants::{ entry_point::ADDRESS, - reputation::{ + validation::reputation::{ BAN_SLACK, MIN_INCLUSION_RATE_DENOMINATOR, MIN_UNSTAKE_DELAY, THROTTLING_SLACK, }, }, @@ -14,7 +15,6 @@ use silius_primitives::{ simulation::CodeHash, UserOperation, UserOperationHash, }; -use silius_uopool::{validate::validator::new_canonical, Mempool, Reputation, UoPoolBuilder}; use std::{ collections::{HashMap, HashSet}, env, @@ -31,18 +31,10 @@ async fn main() -> eyre::Result<()> { let chain = Chain::dev(); let entry_point = EntryPoint::new(provider.clone(), ep); let mempool = Mempool::new( - Arc::new(RwLock::new( - HashMap::::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), + Arc::new(RwLock::new(HashMap::::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), ); let reputation = Reputation::new( MIN_INCLUSION_RATE_DENOMINATOR, @@ -72,10 +64,7 @@ async fn main() -> eyre::Result<()> { println!("In-memory uopool created!"); // size of mempool - println!( - "Mempool size: {size}", - size = builder.uopool().get_all().expect("work").len() - ); + println!("Mempool size: {size}", size = builder.uopool().get_all().expect("work").len()); }; Ok(()) diff --git a/examples/user-operation/Cargo.toml b/examples/user-operation/Cargo.toml index d1625592..f22ededd 100644 --- a/examples/user-operation/Cargo.toml +++ b/examples/user-operation/Cargo.toml @@ -6,16 +6,24 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler examples - user operation -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Account abstraction (ERC-433) examples - user operation" +homepage = "https://github.com/silius-rs/silius/tree/main/examples/user-operation" [dependencies] +# silius dependencies +silius-primitives = { workspace = true } # replace with git url: git = "https://github.com/silius-rs/silius.git" + +# eth ethers = { workspace = true } -eyre = { workspace = true } -silius-primitives = { path = "../../crates/primitives" } + +# tokio tokio = { workspace = true } +# misc +eyre = { workspace = true } + [[example]] name = "user_operation" path = "examples/user_operation.rs" diff --git a/examples/user-operation/examples/user_operation.rs b/examples/user-operation/examples/user_operation.rs index 37f5f02f..9a9b7ca9 100644 --- a/examples/user-operation/examples/user_operation.rs +++ b/examples/user-operation/examples/user_operation.rs @@ -21,13 +21,8 @@ async fn main() -> eyre::Result<()> { println!("User operation hash: {:?}", uo_hash); // sign user operation - let uo_signed = wallet - .sign_uo( - &uo, - &Address::from_str(ENTRY_POINT).unwrap(), - &CHAIN_ID.into(), - ) - .await?; + let uo_signed = + wallet.sign_uo(&uo, &Address::from_str(ENTRY_POINT).unwrap(), &CHAIN_ID.into()).await?; println!("User operation signed: {:?}", uo_signed); Ok(()) diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 2bf5ad04..00000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -stable diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..292fe499 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/rustfmt.toml b/rustfmt.toml index c98788ce..d23b8296 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1,8 @@ -# group_imports = "One" \ No newline at end of file +imports_granularity = "Crate" +use_small_heuristics = "Max" +comment_width = 100 +wrap_comments = true +binop_separator = "Back" +format_code_in_doc_comments = true +doc_comment_code_block_width = 100 +group_imports = "One" diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 420aaff5..c635e8bb 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -6,23 +6,31 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } rust-version = { workspace = true } -description = """ -AA (ERC-4337) bundler integration tests -""" +keywords = { workspace = true } +categories = { workspace = true } +description = "Silius integration tests" +homepage = "https://github.com/silius-rs/silius/tree/main/tests" [dependencies] +# workspace dependencies +silius-contracts = { workspace = true } +silius-mempool = { workspace = true } +silius-primitives = { workspace = true } + +# eth alloy-chains = { workspace = true } ethers = { workspace = true } -eyre = { workspace = true } + +# async parking_lot = { workspace = true } -silius-contracts = { path = "../crates/contracts" } -silius-primitives = { path = "../crates/primitives" } -silius-uopool = { path = "../crates/uopool" } -tempdir = "0.3.7" + +# tokio tokio = { workspace = true } +# misc +eyre = { workspace = true } +tempdir = "0.3.7" + [dev-dependencies] +# async futures = "0.3.28" - -[package.metadata.cargo-udeps.ignore] -normal = ["alloy-chains", "silius-contracts", "silius-primitives", "silius-uopool"] diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..f3334efb --- /dev/null +++ b/tests/README.md @@ -0,0 +1,3 @@ +# silius-tests + +TODO diff --git a/tests/src/common/mod.rs b/tests/src/common/mod.rs index 3810305f..10058caf 100644 --- a/tests/src/common/mod.rs +++ b/tests/src/common/mod.rs @@ -11,13 +11,13 @@ use ethers::{ utils::{Geth, GethInstance}, }; use parking_lot::RwLock; -use silius_primitives::{ - reputation::ReputationEntry, simulation::CodeHash, UserOperation, UserOperationHash, -}; -use silius_uopool::{ +use silius_mempool::{ init_env, CodeHashes, DatabaseTable, EntitiesReputation, Mempool, Reputation, UserOperations, UserOperationsByEntity, UserOperationsBySender, WriteMap, }; +use silius_primitives::{ + reputation::ReputationEntry, simulation::CodeHash, UserOperation, UserOperationHash, +}; use std::{ collections::{HashMap, HashSet}, ops::Mul, @@ -36,10 +36,7 @@ pub struct DeployedContract { } impl DeployedContract { pub fn new(contract: C, addr: Address) -> Self { - Self { - contract, - address: addr, - } + Self { contract, address: addr } } pub fn contract(&self) -> &C { @@ -50,9 +47,7 @@ impl DeployedContract { pub async fn deploy_entry_point( client: Arc, ) -> eyre::Result>> { - let (ep, receipt) = EntryPointContract::deploy(client, ())? - .send_with_receipt() - .await?; + let (ep, receipt) = EntryPointContract::deploy(client, ())?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(ep, addr)) } @@ -61,9 +56,8 @@ pub async fn deploy_simple_account_factory( client: Arc, entry_point_address: Address, ) -> eyre::Result>> { - let (ep, receipt) = SimpleAccountFactory::deploy(client, entry_point_address)? - .send_with_receipt() - .await?; + let (ep, receipt) = + SimpleAccountFactory::deploy(client, entry_point_address)?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(ep, addr)) } @@ -71,9 +65,7 @@ pub async fn deploy_simple_account_factory( pub async fn deploy_test_opcode_account( client: Arc, ) -> eyre::Result>> { - let (acc, receipt) = TestOpcodesAccount::deploy(client, ())? - .send_with_receipt() - .await?; + let (acc, receipt) = TestOpcodesAccount::deploy(client, ())?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(acc, addr)) } @@ -81,9 +73,8 @@ pub async fn deploy_test_opcode_account( pub async fn deploy_test_opcode_account_factory( client: Arc, ) -> eyre::Result>> { - let (factory, receipt) = TestOpcodesAccountFactory::deploy(client, ())? - .send_with_receipt() - .await?; + let (factory, receipt) = + TestOpcodesAccountFactory::deploy(client, ())?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(factory, addr)) } @@ -92,9 +83,8 @@ pub async fn deploy_test_storage_account_factory( client: Arc, test_coin_addr: Address, ) -> eyre::Result>> { - let (factory, receipt) = TestStorageAccountFactory::deploy(client, test_coin_addr)? - .send_with_receipt() - .await?; + let (factory, receipt) = + TestStorageAccountFactory::deploy(client, test_coin_addr)?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(factory, addr)) } @@ -102,9 +92,7 @@ pub async fn deploy_test_storage_account_factory( pub async fn deploy_test_storage_account( client: Arc, ) -> eyre::Result>> { - let (acc, receipt) = TestStorageAccount::deploy(client, ())? - .send_with_receipt() - .await?; + let (acc, receipt) = TestStorageAccount::deploy(client, ())?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(acc, addr)) } @@ -113,9 +101,7 @@ pub async fn deploy_test_recursion_account( client: Arc, ep: Address, ) -> eyre::Result>> { - let (acc, receipt) = TestRecursionAccount::deploy(client, ep)? - .send_with_receipt() - .await?; + let (acc, receipt) = TestRecursionAccount::deploy(client, ep)?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(acc, addr)) } @@ -123,9 +109,8 @@ pub async fn deploy_test_recursion_account( pub async fn deploy_test_rules_account_factory( client: Arc, ) -> eyre::Result>> { - let (factory, receipt) = TestRulesAccountFactory::deploy(client, ())? - .send_with_receipt() - .await?; + let (factory, receipt) = + TestRulesAccountFactory::deploy(client, ())?.send_with_receipt().await?; let addr = receipt.contract_address.unwrap_or(Address::zero()); Ok(DeployedContract::new(factory, addr)) } @@ -149,9 +134,7 @@ pub async fn deploy_test_coin( pub async fn setup_geth() -> eyre::Result<(GethInstance, ClientType, Provider)> { let chain_id: u64 = 1337; let tmp_dir = TempDir::new("test_geth")?; - let wallet = MnemonicBuilder::::default() - .phrase(SEED_PHRASE) - .build()?; + let wallet = MnemonicBuilder::::default().phrase(SEED_PHRASE).build()?; let geth = Geth::new().data_dir(tmp_dir.path().to_path_buf()).spawn(); let provider = @@ -176,14 +159,13 @@ pub fn setup_database_mempool_reputation() -> ( DatabaseTable, DatabaseTable, DatabaseTable, - DatabaseTable, + DatabaseTable, >, Reputation, DatabaseTable>, ) { let dir = TempDir::new("test-silius-db").expect("create tmp"); let env = Arc::new(init_env::(dir.into_path()).expect("Init mdbx failed")); - env.create_tables() - .expect("Create mdbx database tables failed"); + env.create_tables().expect("Create mdbx database tables failed"); let mempool = Mempool::new( DatabaseTable::::new(env.clone()), DatabaseTable::::new(env.clone()), @@ -211,24 +193,16 @@ pub fn setup_memory_mempool_reputation() -> ( Arc>>>, Arc>>>, >, - silius_uopool::Reputation< + silius_mempool::Reputation< Arc>>, Arc>>, >, ) { let mempool = Mempool::new( - Arc::new(RwLock::new( - HashMap::::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), - Arc::new(RwLock::new( - HashMap::>::default(), - )), + Arc::new(RwLock::new(HashMap::::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), + Arc::new(RwLock::new(HashMap::>::default())), ); let reputation = Reputation::new( 10, diff --git a/tests/src/estimate_gas_tests.rs b/tests/src/estimate_gas_tests.rs index 8e7a01fd..4f5427d6 100644 --- a/tests/src/estimate_gas_tests.rs +++ b/tests/src/estimate_gas_tests.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use crate::common::{ deploy_entry_point, deploy_simple_account_factory, gen::{EntryPointContract, SimpleAccountFactory}, @@ -14,10 +12,9 @@ use ethers::{ utils::GethInstance, }; use silius_contracts::EntryPoint; -use silius_primitives::UserOperation; -use silius_primitives::Wallet as UoWallet; -use silius_uopool::validate::validator::new_canonical; -use silius_uopool::UoPool; +use silius_mempool::{validate::validator::new_canonical, UoPool}; +use silius_primitives::{UserOperation, Wallet as UoWallet}; +use std::sync::Arc; async fn setup_basic() -> eyre::Result<( Arc, @@ -59,9 +56,7 @@ macro_rules! estimate_gas_with_init_code { None, ); - let wallet = MnemonicBuilder::::default() - .phrase(SEED_PHRASE) - .build()?; + let wallet = MnemonicBuilder::::default().phrase(SEED_PHRASE).build()?; let owner_address = wallet.address(); let address: H160 = simple_account_factory .contract() @@ -78,9 +73,8 @@ macro_rules! estimate_gas_with_init_code { let _receipt = client.send_transaction(initial_fund, None).await?.await?; let _balance = client.get_balance(address, None).await?; - let call = simple_account_factory - .contract() - .create_account(owner_address, U256::from(1)); + let call = + simple_account_factory.contract().create_account(owner_address, U256::from(1)); let tx: TypedTransaction = call.tx; let mut init_code = Vec::new(); init_code.extend_from_slice(simple_account_factory.address.as_bytes()); @@ -113,24 +107,14 @@ macro_rules! estimate_gas_with_init_code { }; let uo_wallet = UoWallet::from_phrase(SEED_PHRASE, &chain_id.into(), false)?; - let user_op = uo_wallet - .sign_uo(&user_op, &entry_point.address, &chain_id.into()) - .await?; + let user_op = + uo_wallet.sign_uo(&user_op, &entry_point.address, &chain_id.into()).await?; - let res = uopool - .estimate_user_operation_gas(&user_op) - .await - .expect("estimate done"); + let _ = uopool.estimate_user_operation_gas(&user_op).await.expect("estimate done"); Ok(()) } }; } -estimate_gas_with_init_code!( - setup_database_mempool_reputation(), - estimate_gas_init_code_datbase -); -estimate_gas_with_init_code!( - setup_memory_mempool_reputation(), - estimate_gas_init_code_memory -); +estimate_gas_with_init_code!(setup_database_mempool_reputation(), estimate_gas_init_code_datbase); +estimate_gas_with_init_code!(setup_memory_mempool_reputation(), estimate_gas_init_code_memory); diff --git a/tests/src/simulation_tests.rs b/tests/src/simulation_tests.rs index d2b05bd1..2ed3d7df 100644 --- a/tests/src/simulation_tests.rs +++ b/tests/src/simulation_tests.rs @@ -1,44 +1,46 @@ use crate::common::{ - deploy_entry_point, deploy_test_opcode_account, deploy_test_opcode_account_factory, - deploy_test_recursion_account, deploy_test_rules_account_factory, deploy_test_storage_account, + deploy_entry_point, deploy_test_coin, deploy_test_opcode_account, + deploy_test_opcode_account_factory, deploy_test_recursion_account, + deploy_test_rules_account_factory, deploy_test_storage_account, deploy_test_storage_account_factory, gen::{ EntryPointContract, TestOpcodesAccount, TestOpcodesAccountFactory, TestRulesAccount, TestStorageAccountFactory, }, - setup_database_mempool_reputation, setup_geth, ClientType, DeployedContract, + setup_database_mempool_reputation, setup_geth, setup_memory_mempool_reputation, ClientType, + DeployedContract, }; -use crate::common::{deploy_test_coin, setup_memory_mempool_reputation}; use alloy_chains::Chain; -use ethers::abi::Token; -use ethers::prelude::BaseContract; -use ethers::types::transaction::eip2718::TypedTransaction; -use ethers::types::Address; -use ethers::utils::{parse_units, GethInstance}; use ethers::{ + abi::Token, + prelude::BaseContract, providers::Middleware, - types::{Bytes, U256}, + types::{transaction::eip2718::TypedTransaction, Address, Bytes, U256}, + utils::{parse_units, GethInstance}, }; use parking_lot::RwLock; use silius_contracts::EntryPoint; -use silius_primitives::consts::entities::{FACTORY, PAYMASTER, SENDER}; -use silius_primitives::reputation::ReputationEntry; -use silius_primitives::simulation::{CodeHash, SimulationCheckError}; -use silius_primitives::uopool::ValidationError; -use silius_primitives::{UserOperation, UserOperationHash}; - -use silius_uopool::validate::validator::{new_canonical, StandardValidator}; -use silius_uopool::validate::{ - UserOperationValidationOutcome, UserOperationValidator, UserOperationValidatorMode, -}; -use silius_uopool::{ +use silius_mempool::{ + validate::{ + validator::{new_canonical, StandardValidator}, + UserOperationValidationOutcome, UserOperationValidator, UserOperationValidatorMode, + }, CodeHashes, DatabaseTable, EntitiesReputation, HashSetOp, Mempool, Reputation, ReputationEntryOp, UserOperationAct, UserOperationAddrAct, UserOperationCodeHashAct, UserOperations, UserOperationsByEntity, UserOperationsBySender, WriteMap, }; -use std::collections::{HashMap, HashSet}; -use std::ops::Deref; -use std::sync::Arc; +use silius_primitives::{ + constants::validation::entities::{FACTORY, PAYMASTER, SENDER}, + mempool::ValidationError, + reputation::ReputationEntry, + simulation::{CodeHash, SimulationCheckError}, + UserOperation, UserOperationHash, +}; +use std::{ + collections::{HashMap, HashSet}, + ops::Deref, + sync::Arc, +}; struct TestContext where @@ -148,12 +150,8 @@ async fn setup_database() -> eyre::Result { let entry_point = EntryPoint::new(client.clone(), ep.address); let c = Chain::from(chain_id); - let validator = new_canonical( - entry_point, - c.clone(), - U256::from(3000000_u64), - U256::from(1u64), - ); + let validator = + new_canonical(entry_point, c.clone(), U256::from(3000000_u64), U256::from(1u64)); Ok(DatabaseContext { client: client.clone(), @@ -176,12 +174,8 @@ async fn setup_memory() -> eyre::Result { let entry_point = EntryPoint::new(client.clone(), ep.address); let c = Chain::from(chain_id); - let validator = new_canonical( - entry_point, - c.clone(), - U256::from(3000000_u64), - U256::from(1u64), - ); + let validator = + new_canonical(entry_point, c.clone(), U256::from(3000000_u64), U256::from(1u64)); Ok(MemoryContext { client: client.clone(), _geth, @@ -263,10 +257,7 @@ where let (head, address) = call_init_code_for_addr.split_at(12); eyre::ensure!( !head.iter().any(|i| *i != 0), - format!( - "call init code returns non address data : {:?}", - call_init_code_for_addr - ) + format!("call init code returns non address data : {:?}", call_init_code_for_addr) ); let sender = Address::from_slice(address); @@ -387,9 +378,8 @@ macro_rules! accept_plain_request { ($setup:expr, $name: ident) => { #[tokio::test] async fn $name() -> eyre::Result<()> { - let (init_code, init_func) = create_opcode_factory_init_code("".to_string()) - .await - .unwrap(); + let (init_code, init_func) = + create_opcode_factory_init_code("".to_string()).await.unwrap(); let c = $setup; test_user_operation( @@ -464,10 +454,7 @@ macro_rules! fail_with_bad_opcode_in_ctr { } }; } -fail_with_bad_opcode_in_ctr!( - setup_database().await?, - fail_with_bad_opcode_in_ctr_database -); +fail_with_bad_opcode_in_ctr!(setup_database().await?, fail_with_bad_opcode_in_ctr_database); fail_with_bad_opcode_in_ctr!(setup_memory().await?, fail_with_bad_opcode_in_ctr_memory); macro_rules! fail_with_bad_opcode_in_paymaster { @@ -500,10 +487,7 @@ fail_with_bad_opcode_in_paymaster!( setup_database().await?, fail_with_bad_opcode_in_paymaster_database ); -fail_with_bad_opcode_in_paymaster!( - setup_memory().await?, - fail_with_bad_opcode_in_paymaster_memory -); +fail_with_bad_opcode_in_paymaster!(setup_memory().await?, fail_with_bad_opcode_in_paymaster_memory); macro_rules! fail_with_bad_opcode_in_validation { ($setup:expr, $name: ident) => { @@ -576,9 +560,8 @@ macro_rules! fail_referencing_self_token { #[tokio::test] async fn $name() -> eyre::Result<()> { let c = $setup; - let (init_code, init_func) = create_storage_factory_init_code(0, "".to_string()) - .await - .unwrap(); + let (init_code, init_func) = + create_storage_factory_init_code(0, "".to_string()).await.unwrap(); let res = test_user_operation( &c, @@ -591,9 +574,7 @@ macro_rules! fail_referencing_self_token { .await; assert!(matches!( res, - Err(ValidationError::Simulation( - SimulationCheckError::Unstaked { .. } - )) + Err(ValidationError::Simulation(SimulationCheckError::Unstaked { .. })) )); Ok(()) @@ -601,10 +582,7 @@ macro_rules! fail_referencing_self_token { }; } -fail_referencing_self_token!( - setup_database().await?, - fail_referencing_self_token_database -); +fail_referencing_self_token!(setup_database().await?, fail_referencing_self_token_database); fail_referencing_self_token!(setup_memory().await?, fail_referencing_self_token_memory); macro_rules! test_existing_user_operation { @@ -677,9 +655,7 @@ macro_rules! fail_with_unstaked_paymaster_returning_context { #[tokio::test] async fn $name() -> eyre::Result<()> { let c = $setup; - let pm = deploy_test_storage_account(c.client.clone()) - .await - .expect("deploy succeed"); + let pm = deploy_test_storage_account(c.client.clone()).await.expect("deploy succeed"); let acct = deploy_test_recursion_account(c.client.clone(), c.entry_point.address) .await .expect("deploy succeed"); @@ -705,9 +681,7 @@ macro_rules! fail_with_unstaked_paymaster_returning_context { let res = validate(&c, uo).await; assert!(matches!( res, - Err(ValidationError::Simulation( - SimulationCheckError::Unstaked { .. } - )) + Err(ValidationError::Simulation(SimulationCheckError::Unstaked { .. })) )); Ok(()) @@ -749,9 +723,7 @@ macro_rules! fail_with_validation_recursively_calls_handle_ops { let res = validate(&c, uo).await; assert!(matches!( res, - Err(ValidationError::Simulation( - SimulationCheckError::CallStack { .. } - )) + Err(ValidationError::Simulation(SimulationCheckError::CallStack { .. })) )); Ok(()) @@ -772,9 +744,8 @@ macro_rules! succeed_with_inner_revert { #[tokio::test] async fn $name() -> eyre::Result<()> { let c = $setup; - let (init_code, init_func) = create_storage_factory_init_code(0, "".to_string()) - .await - .unwrap(); + let (init_code, init_func) = + create_storage_factory_init_code(0, "".to_string()).await.unwrap(); test_user_operation( &c, "inner-revert".to_string(), @@ -798,9 +769,8 @@ macro_rules! fail_with_inner_oog_revert { #[tokio::test] async fn $name() -> eyre::Result<()> { let c = $setup; - let (init_code, init_func) = create_storage_factory_init_code(0, "".to_string()) - .await - .unwrap(); + let (init_code, init_func) = + create_storage_factory_init_code(0, "".to_string()).await.unwrap(); let res = test_user_operation( &c, @@ -813,9 +783,7 @@ macro_rules! fail_with_inner_oog_revert { .await; assert!(matches!( res, - Err(ValidationError::Simulation( - SimulationCheckError::OutOfGas { .. } - )) + Err(ValidationError::Simulation(SimulationCheckError::OutOfGas { .. })) )); Ok(()) diff --git a/tests/src/tracer_tests.rs b/tests/src/tracer_tests.rs index 340d660d..78b62101 100644 --- a/tests/src/tracer_tests.rs +++ b/tests/src/tracer_tests.rs @@ -28,20 +28,14 @@ async fn setup() -> eyre::Result> { let client = Arc::new(_client); let tracer_test = deploy_tracer_test(client.clone()).await?; - Ok(Context { - _geth, - client, - tracer_test, - }) + Ok(Context { _geth, client, tracer_test }) } async fn trace_call( c: &Context, func_data: Bytes, ) -> eyre::Result { - let req = TransactionRequest::new() - .to(c.tracer_test.address) - .data(func_data); + let req = TransactionRequest::new().to(c.tracer_test.address).data(func_data); let res = c .client .clone() @@ -89,10 +83,7 @@ async fn trace_exec_self( async fn count_opcode_depth_bigger_than_1() -> eyre::Result<()> { let c = setup().await?; let contract: &BaseContract = c.tracer_test.contract().deref().deref(); - let func_data = contract - .abi() - .function("callTimeStamp")? - .encode_input(&[])?; + let func_data = contract.abi().function("callTimeStamp")?.encode_input(&[])?; let ret = trace_exec_self(&c, func_data, false, true).await?; let log: ExecSelfResultFilter = ExecSelfResultFilter::decode_log(&RawLog::from(( ret.logs[0] @@ -104,13 +95,7 @@ async fn count_opcode_depth_bigger_than_1() -> eyre::Result<()> { ret.logs[0].data.to_vec(), )))?; assert_eq!(log.success, true); - assert_eq!( - *ret.calls_from_entry_point[0] - .opcodes - .get("TIMESTAMP") - .unwrap(), - 1 - ); + assert_eq!(*ret.calls_from_entry_point[0].opcodes.get("TIMESTAMP").unwrap(), 1); Ok(()) } @@ -118,14 +103,7 @@ async fn count_opcode_depth_bigger_than_1() -> eyre::Result<()> { async fn trace_exec_self_should_revert() -> eyre::Result<()> { let c = setup().await?; let ret = trace_exec_self(&c, Bytes::from_str("0xdead")?.to_vec(), true, true).await?; - assert!( - ret.debug - .join(",") - .matches("execution reverted") - .collect::>() - .len() - > 0 - ); + assert!(ret.debug.join(",").matches("execution reverted").collect::>().len() > 0); assert_eq!(ret.logs.len(), 1); let log: ExecSelfResultFilter = ExecSelfResultFilter::decode_log(&RawLog::from(( @@ -173,10 +151,7 @@ async fn should_report_direct_use_of_gas_opcode() -> eyre::Result<()> { let contract: &BaseContract = c.tracer_test.contract().deref().deref(); let func_data = contract.abi().function("testCallGas")?.encode_input(&[])?; let ret = trace_exec_self(&c, func_data, false, false).await?; - assert_eq!( - *ret.calls_from_entry_point[0].opcodes.get("GAS").unwrap(), - 1 - ); + assert_eq!(*ret.calls_from_entry_point[0].opcodes.get("GAS").unwrap(), 1); Ok(()) } diff --git a/tomlfmt.toml b/tomlfmt.toml new file mode 100644 index 00000000..479bb7e9 --- /dev/null +++ b/tomlfmt.toml @@ -0,0 +1 @@ +key_value_newlines = true