diff --git a/Cargo.lock b/Cargo.lock index 73bcf92a7..c89a99e89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -59,6 +69,17 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.4.4", + "cpufeatures 0.2.12", +] + [[package]] name = "aes-gcm" version = "0.8.0" @@ -474,7 +495,7 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.1.1", "async-executor", - "async-io 2.2.2", + "async-io 2.3.0", "async-lock 3.3.0", "blocking", "futures-lite 2.2.0", @@ -503,9 +524,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7" +checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744" dependencies = [ "async-lock 3.3.0", "cfg-if 1.0.0", @@ -513,7 +534,7 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.3.1", + "polling 3.3.2", "rustix 0.38.30", "slab", "tracing", @@ -572,7 +593,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" dependencies = [ - "async-io 2.2.2", + "async-io 2.3.0", "async-lock 2.8.0", "atomic-waker", "cfg-if 1.0.0", @@ -781,6 +802,12 @@ dependencies = [ "regex", ] +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "beef" version = "0.5.2" @@ -930,6 +957,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2 0.10.8", + "tinyvec", +] + [[package]] name = "build_const" version = "0.2.2" @@ -995,6 +1032,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "c-kzg" version = "0.1.0" @@ -1022,6 +1080,38 @@ dependencies = [ "libc", ] +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.21", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "castaway" version = "0.1.2" @@ -1098,6 +1188,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.7.0" @@ -1111,9 +1211,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.16" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e54881c004cec7895b0068a0a954cd5d62da01aef83fa35b1e594497bf5445" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -1121,9 +1221,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.16" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cb82d7f531603d2fd1f507441cdd35184fa81beff7bd489570de7f773460bb" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -1171,6 +1271,58 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac 0.12.1", + "k256", + "serde", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -1211,6 +1363,12 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.4.0" @@ -1417,6 +1575,15 @@ dependencies = [ "cipher 0.3.0", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "curl" version = "0.4.44" @@ -1546,6 +1713,12 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + [[package]] name = "delay_map" version = "0.1.2" @@ -1643,7 +1816,16 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", ] [[package]] @@ -1667,6 +1849,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1715,6 +1909,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "ecdsa" version = "0.16.9" @@ -1893,6 +2093,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes 0.8.3", + "ctr 0.9.2", + "digest 0.10.7", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", + "uuid 0.8.2", +] + [[package]] name = "eth2_hashing" version = "0.2.0" @@ -2015,6 +2237,93 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ethers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5344eea9b20effb5efeaad29418215c4d27017639fd1f908260f59cbbd226e" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf35eb7d2e2092ad41f584951e08ec7c077b142dba29c4f1b8f52d2efddc49c" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0111ead599d17a7bff6985fd5756f39ca7033edc79a31b23026a8d5d64fa95cd" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbdfb952aafd385b31d316ed80d7b76215ce09743c172966d840e96924427e0c" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "ethers-etherscan", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "reqwest", + "serde", + "serde_json", + "syn 2.0.48", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7465c814a2ecd0de0442160da13584205d1cdc08f4717a6511cad455bd5d7dc4" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.48", +] + [[package]] name = "ethers-core" version = "2.0.12" @@ -2023,6 +2332,7 @@ checksum = "918b1a9ba585ea61022647def2f27c29ba19f6d2a4a4c8f68a9ae97fd5769737" dependencies = [ "arrayvec", "bytes 1.5.0", + "cargo_metadata", "chrono", "const-hex", "elliptic-curve", @@ -2030,18 +2340,63 @@ dependencies = [ "generic-array", "k256", "num_enum", + "once_cell", "open-fastrlp", "rand 0.8.5", "rlp", "serde", "serde_json", "strum 0.25.0", + "syn 2.0.48", "tempfile", "thiserror", "tiny-keccak", "unicode-xid", ] +[[package]] +name = "ethers-etherscan" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "facabf8551b4d1a3c08cb935e7fca187804b6c2525cc0dafb8e5a6dd453a24de" +dependencies = [ + "chrono", + "ethers-core", + "reqwest", + "semver 1.0.21", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681ece6eb1d10f7cf4f873059a77c04ff1de4f35c63dd7bccde8f438374fcb93" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + [[package]] name = "ethers-providers" version = "2.0.11" @@ -2064,20 +2419,72 @@ dependencies = [ "instant", "jsonwebtoken", "once_cell", - "pin-project", - "reqwest", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winapi 0.3.9", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb1b714e227bbd2d8c53528adb580b203009728b17d0d0e4119353aa9bc5532" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2e46e3ec8ef0c986145901fa9864205dc4dcee701f9846be2d56112d34bdea" +dependencies = [ + "cfg-if 1.0.0", + "const-hex", + "dirs", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver 1.0.21", "serde", "serde_json", + "solang-parser", + "svm-rs", "thiserror", + "tiny-keccak", "tokio", "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winapi 0.3.9", - "ws_stream_wasm", + "walkdir", + "yansi 0.5.1", ] [[package]] @@ -2207,6 +2614,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "eyre" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -2329,6 +2746,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -2439,6 +2866,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -3055,6 +3492,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.3" @@ -3089,6 +3532,15 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -3708,6 +4160,16 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if 1.0.0", + "digest 0.10.7", +] + [[package]] name = "md5" version = "0.7.0" @@ -4037,6 +4499,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "overload" version = "0.1.1" @@ -4164,12 +4632,51 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", + "password-hash", + "sha2 0.10.8", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + [[package]] name = "pear" version = "0.2.8" @@ -4178,7 +4685,7 @@ checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" dependencies = [ "inlinable_string", "pear_codegen", - "yansi", + "yansi 1.0.0-rc.1", ] [[package]] @@ -4245,6 +4752,39 @@ dependencies = [ "rustc_version 0.4.0", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "phf_shared" version = "0.10.0" @@ -4254,6 +4794,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pico-args" version = "0.5.0" @@ -4343,9 +4892,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" dependencies = [ "cfg-if 1.0.0", "concurrent-queue", @@ -4582,7 +5131,7 @@ dependencies = [ "quote", "syn 2.0.48", "version_check", - "yansi", + "yansi 1.0.0-rc.1", ] [[package]] @@ -5206,6 +5755,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rlp" version = "0.5.2" @@ -5520,6 +6078,15 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "same-file" version = "1.0.6" @@ -5578,6 +6145,18 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "salsa20", + "sha2 0.10.8", +] + [[package]] name = "sct" version = "0.7.1" @@ -5667,6 +6246,9 @@ name = "semver" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" @@ -5870,6 +6452,17 @@ dependencies = [ "sha1_smol", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures 0.2.12", + "digest 0.10.7", +] + [[package]] name = "sha1_smol" version = "1.0.0" @@ -6057,6 +6650,20 @@ dependencies = [ "sha-1", ] +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + [[package]] name = "spin" version = "0.5.2" @@ -6203,7 +6810,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot 0.12.1", - "phf_shared", + "phf_shared 0.10.0", "precomputed-hash", ] @@ -6337,6 +6944,26 @@ dependencies = [ "web-sys", ] +[[package]] +name = "svm-rs" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20689c7d03b6461b502d0b95d6c24874c7d24dea2688af80486a130a06af3b07" +dependencies = [ + "dirs", + "fs2", + "hex", + "once_cell", + "reqwest", + "semver 1.0.21", + "serde", + "serde_json", + "sha2 0.10.8", + "thiserror", + "url", + "zip", +] + [[package]] name = "syn" version = "1.0.109" @@ -6722,6 +7349,21 @@ dependencies = [ "tokio-executor", ] +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + [[package]] name = "tokio-udp" version = "0.1.6" @@ -6872,7 +7514,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", - "uuid", + "uuid 1.6.1", ] [[package]] @@ -7019,10 +7661,12 @@ dependencies = [ "discv5", "ethereum-types", "ethereum_ssz", + "ethers", "ethers-core", "ethers-providers", "ethportal-api", "ethportal-peertest", + "futures 0.3.30", "jsonrpsee", "lazy_static", "parking_lot 0.11.2", @@ -7047,6 +7691,7 @@ dependencies = [ "trin-utils", "trin-validation", "ureq", + "url", "utp-rs", ] @@ -7200,6 +7845,26 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes 1.5.0", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls", + "sha1 0.10.6", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" version = "1.17.0" @@ -7350,6 +8015,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" version = "0.2.1" @@ -7388,6 +8059,16 @@ dependencies = [ "utp-rs", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.12", + "serde", +] + [[package]] name = "uuid" version = "1.6.1" @@ -7847,6 +8528,12 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "yansi" version = "1.0.0-rc.1" @@ -7893,6 +8580,35 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes 0.8.3", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils 0.8.19", + "flate2", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "sha1 0.10.6", + "time 0.3.31", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.12.4" @@ -7911,6 +8627,16 @@ dependencies = [ "zstd-safe 7.0.0", ] +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-safe" version = "6.0.6" diff --git a/Cargo.toml b/Cargo.toml index c66bd2673..a26db20ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,10 @@ clap = { version = "4.2.1", features = ["derive"] } discv5 = { version = "0.4.0", features = ["serde"] } ethereum-types = "0.14.1" ethereum_ssz = "0.5.3" +ethers = { version = "2.0"} +ethers-providers = { version = "2.0", features = ["ws"] } ethportal-api = { path = "ethportal-api" } +futures = "0.3.21" jsonrpsee = "0.20.0" lazy_static = "1.4.0" parking_lot = "0.11.2" @@ -40,6 +43,7 @@ trin-state = { path = "trin-state" } trin-storage = { path = "trin-storage" } trin-utils = { path = "trin-utils" } trin-validation = { path = "trin-validation" } +url = "2.3.1" utp-rs = "0.1.0-alpha.8" [dev-dependencies] diff --git a/docker/Dockerfile b/docker/Dockerfile index 28b2fd1cd..66c87eb83 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -39,6 +39,8 @@ FROM ubuntu:22.04 # copy build artifacts from build stage COPY --from=builder /trin/target/release/trin /usr/bin/ +COPY --from=builder /trin/target/release/poll_latest /usr/bin/ +COPY --from=builder /trin/target/release/sample_range /usr/bin/ ENV RUST_LOG=debug diff --git a/docker/Dockerfile.bridge b/docker/Dockerfile.bridge index 4fe0f3dbd..61f0c08ec 100644 --- a/docker/Dockerfile.bridge +++ b/docker/Dockerfile.bridge @@ -41,6 +41,8 @@ FROM ubuntu:22.04 # copy build artifacts from build stage COPY --from=builder /trin/target/release/trin /usr/bin/ COPY --from=builder /trin/target/release/portal-bridge /usr/bin/ +COPY --from=builder /trin/target/release/sample_range /usr/bin/ +COPY --from=builder /trin/target/release/poll_latest /usr/bin/ # These steps copy over the epoch accumulators repo for the bridge to use # This data is too large to be kept inside trin-source code # It must be downloaded separately and moved to the correct location diff --git a/src/bin/poll_latest.rs b/src/bin/poll_latest.rs new file mode 100644 index 000000000..96e57c57d --- /dev/null +++ b/src/bin/poll_latest.rs @@ -0,0 +1,313 @@ +use anyhow::{anyhow, Result}; +use clap::Parser; +use ethereum_types::H256; +use ethers::prelude::*; +use ethers_providers::Ws; +use ethportal_api::{ + jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, + types::{ + content_key::overlay::OverlayContentKey, + content_value::history::PossibleHistoryContentValue, history::ContentInfo, + }, + BlockBodyKey, BlockHeaderKey, BlockReceiptsKey, HistoryContentKey, HistoryNetworkApiClient, +}; +use std::{ + str::FromStr, + sync::{Arc, Mutex}, + time::Instant, +}; +use tokio::time::{sleep, Duration}; +use tracing::{debug, info, warn}; +use url::Url; + +use trin_utils::log::init_tracing_logger; + +// tldr; +// to poll latest blocks +// cargo run --bin poll_latest +// to poll latest blocks with exponential backoff and give up trying +// to find a piece of data after 240 seconds: +// cargo run --bin poll_latest -- --timeout 240 +// to poll latest blocks, and retry every 3 seconds if the data is not found: +// cargo run --bin poll_latest -- --backoff linear:3 + +const DEFAULT_NODE_IP: &str = "http://127.0.0.1:8545"; + +#[derive(Default)] +struct Metrics { + header: Details, + block_body: Details, + receipts: Details, + // the active audit count measures every individual, active, RFC lookup + active_audit_count: u32, + // the complete audit count measures the total number of blocks whose audits have completed + complete_audit_count: u32, +} + +impl Metrics { + fn display_stats(&self) { + info!( + "Audits (active/complete): {:?}/{:?} // Headers {:?}% @ {:.2?} // Bodies {:?}% @ {:.2?} // Receipts {:?}% @ {:.2?}", + self.active_audit_count, + self.complete_audit_count, + (self.header.success_count * 100) / self.header.total_count(), + self.header.average_time, + (self.block_body.success_count * 100) / self.block_body.total_count(), + self.block_body.average_time, + (self.receipts.success_count * 100) / self.receipts.total_count(), + self.receipts.average_time); + debug!( + "Headers: {:?}/{:?} // Bodies: {:?}/{:?} // Receipts: {:?}/{:?}", + self.header.success_count, + self.header.total_count(), + self.block_body.success_count, + self.block_body.total_count(), + self.receipts.success_count, + self.receipts.total_count(), + ); + } +} + +pub const MAX_TIMEOUT: Duration = Duration::from_secs(240); + +#[derive(Debug, Default)] +struct Details { + success_count: u32, + failure_count: u32, + average_time: Duration, +} + +impl Details { + fn total_count(&self) -> u32 { + self.success_count + self.failure_count + } + + fn report_success(&mut self, new_time: Duration) { + self.average_time = + (self.average_time * self.success_count + new_time) / (self.success_count + 1); + self.success_count += 1; + } + + fn report_failure(&mut self) { + // don't update average time on failure + self.failure_count += 1; + } +} + +#[tokio::main] +pub async fn main() -> Result<()> { + init_tracing_logger(); + info!("Running Poll Latest script."); + let audit_config = AuditConfig::parse(); + let timeout = match audit_config.timeout { + Some(timeout) => Duration::from_secs(timeout), + None => MAX_TIMEOUT, + }; + let infura_project_id = std::env::var("TRIN_INFURA_PROJECT_ID")?; + let ws = Provider::::connect(format!("wss://mainnet.infura.io/ws/v3/{infura_project_id}")) + .await?; + let mut stream = ws.subscribe_blocks().await?; + let client = HttpClientBuilder::default().build(audit_config.node_ip)?; + let metrics = Arc::new(Mutex::new(Metrics::default())); + while let Some(block) = stream.next().await { + let block_hash = block.hash.unwrap(); + info!("Found new block {block_hash}"); + let timestamp = Instant::now(); + let metrics = metrics.clone(); + tokio::spawn(audit_block( + block_hash, + timestamp, + timeout, + audit_config.backoff, + metrics, + client.clone(), + )); + } + Ok(()) +} + +async fn audit_block( + hash: H256, + timestamp: Instant, + timeout: Duration, + backoff: Backoff, + metrics: Arc>, + client: HttpClient, +) -> Result<()> { + metrics.lock().unwrap().active_audit_count += 3; + let header_handle = tokio::spawn(audit_content_key( + HistoryContentKey::BlockHeaderWithProof(BlockHeaderKey { + block_hash: hash.to_fixed_bytes(), + }), + timestamp, + timeout, + backoff, + client.clone(), + )); + let block_body_handle = tokio::spawn(audit_content_key( + HistoryContentKey::BlockBody(BlockBodyKey { + block_hash: hash.to_fixed_bytes(), + }), + timestamp, + timeout, + backoff, + client.clone(), + )); + let receipts_handle = tokio::spawn(audit_content_key( + HistoryContentKey::BlockReceipts(BlockReceiptsKey { + block_hash: hash.to_fixed_bytes(), + }), + timestamp, + timeout, + backoff, + client.clone(), + )); + match header_handle.await? { + Ok(found_time) => { + let mut metrics = metrics.lock().unwrap(); + metrics.active_audit_count -= 1; + let time_diff = found_time - timestamp; + metrics.header.report_success(time_diff); + } + Err(_) => { + let mut metrics = metrics.lock().unwrap(); + metrics.active_audit_count -= 1; + metrics.header.report_failure(); + } + } + match block_body_handle.await? { + Ok(found_time) => { + let mut metrics = metrics.lock().unwrap(); + metrics.active_audit_count -= 1; + let time_diff = found_time - timestamp; + metrics.block_body.report_success(time_diff); + } + Err(_) => { + let mut metrics = metrics.lock().unwrap(); + metrics.block_body.report_failure(); + metrics.active_audit_count -= 1; + } + } + match receipts_handle.await? { + Ok(found_time) => { + let mut metrics = metrics.lock().unwrap(); + metrics.active_audit_count -= 1; + let time_diff = found_time - timestamp; + metrics.receipts.report_success(time_diff); + } + Err(_) => { + let mut metrics = metrics.lock().unwrap(); + metrics.receipts.report_failure(); + metrics.active_audit_count -= 1; + } + } + let mut metrics = metrics.lock().unwrap(); + metrics.complete_audit_count += 1; + metrics.display_stats(); + Ok(()) +} + +async fn audit_content_key( + content_key: HistoryContentKey, + timestamp: Instant, + timeout: Duration, + backoff: Backoff, + client: HttpClient, +) -> anyhow::Result { + let mut attempts = 0; + while Instant::now() - timestamp < timeout { + let content = client.recursive_find_content(content_key.clone()).await?; + if let ContentInfo::Content { content, .. } = content { + if let PossibleHistoryContentValue::ContentPresent(_) = content { + return Ok(Instant::now()); + } else { + attempts += 1; + let sleep_time = match backoff { + Backoff::Exponential => attempts * 2, + Backoff::Linear(delay) => delay, + }; + sleep(Duration::from_secs(sleep_time)).await; + } + } + } + let err_msg = format!( + "Unable to find content_key: {:?} within {timeout:?}", + content_key.to_hex(), + ); + warn!("{}", err_msg); + Err(anyhow!("{}", err_msg)) +} + +// CLI Parameter Handling +#[derive(Parser, Debug, PartialEq)] +#[command( + name = "Poll Latest Audit Configuration", + about = "Script to poll availability of latest data" +)] +pub struct AuditConfig { + #[arg(long, help = "max timeout in seconds")] + pub timeout: Option, + + #[arg( + long, + help = "mode for backoff (eg. 'exponential' / 'linear:3' for every 3 seconds)", + default_value = "exponential" + )] + pub backoff: Backoff, + + #[arg(long, help = "ip address of node", default_value = DEFAULT_NODE_IP)] + pub node_ip: Url, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum Backoff { + Linear(u64), + Exponential, +} + +type ParseError = &'static str; + +impl FromStr for Backoff { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + match s { + "exponential" => Ok(Self::Exponential), + val => { + let index = val.find(':').ok_or("Invalid backoff: unable to find `:`")?; + let (mode, val) = val.split_at(index); + match mode { + "linear" => { + let val = val.trim_start_matches(':'); + let val = val + .parse::() + .map_err(|_| "Invalid backoff: unable to parse delay")?; + Ok(Self::Linear(val)) + } + _ => Err("Invalid backoff: unsupported mode."), + } + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_detail() { + let mut details = Details::default(); + assert_eq!(details.total_count(), 0); + details.report_success(Duration::from_secs(1)); + assert_eq!(details.total_count(), 1); + assert_eq!(details.average_time, Duration::from_secs(1)); + details.report_failure(); + assert_eq!(details.total_count(), 2); + details.report_success(Duration::from_secs(3)); + assert_eq!(details.total_count(), 3); + assert_eq!(details.average_time, Duration::from_secs(2)); + details.report_failure(); + assert_eq!(details.total_count(), 4); + } +} diff --git a/src/bin/sample_range.rs b/src/bin/sample_range.rs new file mode 100644 index 000000000..fccac9490 --- /dev/null +++ b/src/bin/sample_range.rs @@ -0,0 +1,225 @@ +use std::{ + str::FromStr, + sync::{Arc, Mutex}, +}; + +use anyhow::Result; +use clap::Parser; +use ethereum_types::H256; +use ethers::prelude::*; +use ethers_providers::Http; +use rand::{distributions::Uniform, thread_rng, Rng}; +use tracing::{debug, info, warn}; +use url::Url; + +use ethportal_api::{ + jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, + types::{content_value::history::PossibleHistoryContentValue, history::ContentInfo}, + BlockBodyKey, BlockHeaderKey, BlockReceiptsKey, HistoryContentKey, HistoryNetworkApiClient, +}; +use trin_utils::log::init_tracing_logger; +use trin_validation::constants::MERGE_BLOCK_NUMBER; + +// tldr +// to sample 5 blocks from the shanghai fork: +// cargo run --bin sample_range -- --sample-size 5 --range shanghai +// to sample 50 blocks from the since block #100000: +// cargo run --bin sample_range -- --sample-size 50 --range since:100000 +// to sample 5 blocks from the latest 500 blocks: +// cargo run --bin sample_range -- --sample-size 5 --range latest:500 + +#[derive(Default)] +struct Metrics { + header: Details, + block_body: Details, + receipts: Details, +} + +impl Metrics { + fn display_stats(&self) { + info!( + "Headers {:?}% // Bodies {:?}% // Receipts {:?}%", + (self.header.success_count * 100) / self.header.total_count(), + (self.block_body.success_count * 100) / self.block_body.total_count(), + (self.receipts.success_count * 100) / self.receipts.total_count() + ); + debug!( + "Headers: {:?}/{:?} // Bodies: {:?}/{:?} // Receipts: {:?}/{:?}", + self.header.success_count, + self.header.total_count(), + self.block_body.success_count, + self.block_body.total_count(), + self.receipts.success_count, + self.receipts.total_count() + ); + } +} + +const FUTURES_BUFFER_SIZE: usize = 8; +const SHANGHAI_BLOCK_NUMBER: u64 = 17034870; +const DEFAULT_NODE_IP: &str = "http://127.0.0.1:8545"; + +#[derive(Debug, Default)] +struct Details { + success_count: u32, + failure_count: u32, +} + +impl Details { + fn total_count(&self) -> u32 { + self.success_count + self.failure_count + } +} + +#[tokio::main] +pub async fn main() -> Result<()> { + init_tracing_logger(); + let audit_config = SampleConfig::parse(); + info!("Running Sample Range Audit: {:?}", audit_config.range); + let infura_project_id = std::env::var("TRIN_INFURA_PROJECT_ID")?; + let provider = + Provider::::connect(&format!("https://mainnet.infura.io/v3/{infura_project_id}")) + .await; + let client = HttpClientBuilder::default().build(audit_config.node_ip)?; + let latest_block: u64 = provider.get_block_number().await?.try_into().unwrap(); + let block_range = match audit_config.range { + SampleRange::Shanghai => Uniform::new_inclusive(SHANGHAI_BLOCK_NUMBER, latest_block), + SampleRange::FourFours => Uniform::new_inclusive(0, MERGE_BLOCK_NUMBER), + SampleRange::Since(since) => Uniform::new_inclusive(since, latest_block), + SampleRange::Latest(latest) => Uniform::from(latest_block - latest..latest_block), + }; + info!( + "Sampling {} Blocks from Range: {:?}", + audit_config.sample_size, block_range + ); + let mut rng = thread_rng(); + let blocks: Vec = (&mut rng) + .sample_iter(block_range) + .take(audit_config.sample_size) + .collect(); + let metrics = Arc::new(Mutex::new(Metrics::default())); + let futures = futures::stream::iter(blocks.into_iter().map(|block_number| { + let client = client.clone(); + let metrics = metrics.clone(); + let provider = provider.clone(); + async move { + let block_hash = provider + .get_block(block_number) + .await + .unwrap() + .unwrap() + .hash + .unwrap(); + let _ = audit_block(block_hash, metrics, client).await; + } + })) + .buffer_unordered(FUTURES_BUFFER_SIZE) + .collect::>(); + futures.await; + metrics.lock().unwrap().display_stats(); + Ok(()) +} + +async fn audit_block( + hash: H256, + metrics: Arc>, + client: HttpClient, +) -> anyhow::Result<()> { + let header_ck = HistoryContentKey::BlockHeaderWithProof(BlockHeaderKey { + block_hash: hash.to_fixed_bytes(), + }); + let body_ck = HistoryContentKey::BlockBody(BlockBodyKey { + block_hash: hash.to_fixed_bytes(), + }); + let receipts_ck = HistoryContentKey::BlockReceipts(BlockReceiptsKey { + block_hash: hash.to_fixed_bytes(), + }); + match client.recursive_find_content(header_ck).await? { + ContentInfo::Content { content, .. } => { + if let PossibleHistoryContentValue::ContentPresent(_) = content { + metrics.lock().unwrap().header.success_count += 1; + } else { + warn!("Header not found for block {hash}"); + metrics.lock().unwrap().header.failure_count += 1; + } + } + _ => metrics.lock().unwrap().header.failure_count += 1, + } + match client.recursive_find_content(body_ck).await? { + ContentInfo::Content { content, .. } => { + if let PossibleHistoryContentValue::ContentPresent(_) = content { + metrics.lock().unwrap().block_body.success_count += 1; + } else { + warn!("Body not found for block {hash}"); + metrics.lock().unwrap().block_body.failure_count += 1; + } + } + _ => metrics.lock().unwrap().block_body.failure_count += 1, + } + match client.recursive_find_content(receipts_ck).await? { + ContentInfo::Content { content, .. } => { + if let PossibleHistoryContentValue::ContentPresent(_) = content { + metrics.lock().unwrap().receipts.success_count += 1; + } else { + warn!("Receipts not found for block {hash}"); + metrics.lock().unwrap().receipts.failure_count += 1; + } + } + _ => metrics.lock().unwrap().receipts.failure_count += 1, + } + Ok(()) +} + +// CLI Parameter Handling +#[derive(Parser, Debug, PartialEq)] +#[command( + name = "Sample Config", + about = "Script to sample random blocks from a specified range" +)] +pub struct SampleConfig { + #[arg( + long, + help = "Range to sample blocks from (shanghai, fourfours, since:123, latest:123)" + )] + pub range: SampleRange, + + #[arg(long, help = "Number of blocks to sample")] + pub sample_size: usize, + + #[arg(long, help = "ip address of node", default_value = DEFAULT_NODE_IP)] + pub node_ip: Url, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum SampleRange { + FourFours, + Shanghai, + Since(u64), + Latest(u64), +} + +type ParseError = &'static str; + +impl FromStr for SampleRange { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + match s { + "fourfours" => Ok(Self::FourFours), + "shanghai" => Ok(Self::Shanghai), + val => { + let index = val.find(':').ok_or("Invalid sample range, missing `:`")?; + let (mode, val) = val.split_at(index); + let val = val.trim_start_matches(':'); + let block = val + .parse::() + .map_err(|_| "Invalid sample range: unable to parse block number")?; + match mode { + "since" => Ok(Self::Since(block)), + "latest" => Ok(Self::Latest(block)), + _ => Err("Invalid sample range: invalid mode"), + } + } + } + } +}