diff --git a/Cargo.lock b/Cargo.lock index 09321e79..07a932ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,7 +128,7 @@ dependencies = [ "either", "k256", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "secp256k1 0.30.0", "serde", "serde_json", @@ -178,7 +178,7 @@ dependencies = [ "alloy-rlp", "arbitrary", "crc", - "rand 0.8.5", + "rand 0.8.6", "serde", "thiserror 2.0.18", ] @@ -193,7 +193,7 @@ dependencies = [ "alloy-rlp", "arbitrary", "borsh", - "rand 0.8.5", + "rand 0.8.6", "serde", ] @@ -208,7 +208,7 @@ dependencies = [ "arbitrary", "borsh", "k256", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_with", "thiserror 2.0.18", @@ -393,7 +393,7 @@ dependencies = [ "paste", "proptest", "proptest-derive", - "rand 0.9.2", + "rand 0.9.3", "rapidhash", "ruint", "rustc-hash", @@ -610,7 +610,7 @@ dependencies = [ "ethereum_ssz 0.9.1", "ethereum_ssz_derive 0.9.1", "jsonwebtoken", - "rand 0.8.5", + "rand 0.8.6", "serde", "strum", ] @@ -719,7 +719,7 @@ dependencies = [ "coins-bip32", "coins-bip39", "k256", - "rand 0.8.5", + "rand 0.8.6", "thiserror 2.0.18", "zeroize", ] @@ -1258,7 +1258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1268,7 +1268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1278,7 +1278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1464,6 +1464,7 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-rpc-types-trace", "alloy-serde", + "alloy-signer", "alloy-signer-local", "alloy-sol-macro", "alloy-sol-types", @@ -1471,16 +1472,22 @@ dependencies = [ "bytes", "clap", "derive_more", + "dirs", "eyre", + "futures", "jsonrpsee", "jsonrpsee-core", "jsonrpsee-proc-macros", + "libc", "modular-bitfield", + "rand 0.8.6", + "reedline", "reth", "reth-basic-payload-builder", "reth-chainspec", "reth-cli", "reth-cli-commands", + "reth-cli-runner", "reth-cli-util", "reth-codecs", "reth-consensus-common", @@ -1490,13 +1497,18 @@ dependencies = [ "reth-engine-local", "reth-engine-primitives", "reth-errors", + "reth-eth-wire-types", "reth-ethereum-cli", "reth-ethereum-engine-primitives", "reth-ethereum-payload-builder", "reth-ethereum-primitives", "reth-evm", "reth-evm-ethereum", + "reth-metrics", + "reth-network", + "reth-network-api", "reth-network-peers", + "reth-network-types", "reth-node-api", "reth-node-builder", "reth-node-core", @@ -1510,17 +1522,21 @@ dependencies = [ "reth-rpc-engine-api", "reth-rpc-eth-api", "reth-rpc-eth-types", + "reth-rpc-server-types", "reth-storage-api", "reth-transaction-pool", "reth-trie-common", "revm-inspectors", + "rusqlite", "serde", "serde_json", "sha2", + "tempfile", "test-fuzz", "thiserror 2.0.18", "tokio", "tracing", + "tracing-subscriber 0.3.22", "vergen", "vergen-git2", ] @@ -1718,7 +1734,7 @@ dependencies = [ "num_enum", "paste", "portable-atomic", - "rand 0.9.2", + "rand 0.9.3", "regress", "rustc-hash", "ryu-js", @@ -2150,7 +2166,7 @@ dependencies = [ "hmac", "once_cell", "pbkdf2", - "rand 0.8.5", + "rand 0.8.6", "sha2", "thiserror 1.0.69", ] @@ -2424,6 +2440,7 @@ dependencies = [ "mio", "parking_lot", "rustix", + "serde", "signal-hook", "signal-hook-mio", "winapi", @@ -2647,7 +2664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 2.0.114", + "syn 1.0.109", ] [[package]] @@ -2867,7 +2884,7 @@ dependencies = [ "more-asserts", "multiaddr", "parking_lot", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "socket2 0.5.10", "tokio", @@ -3028,7 +3045,7 @@ dependencies = [ "hex", "k256", "log", - "rand 0.8.5", + "rand 0.8.6", "secp256k1 0.30.0", "serde", "sha3", @@ -3191,6 +3208,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fast-float2" version = "0.2.3" @@ -3225,6 +3254,17 @@ dependencies = [ "bytes", ] +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "fdlimit" version = "0.3.0" @@ -3286,7 +3326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.5", + "rand 0.8.6", "rustc-hex", "static_assertions", ] @@ -3397,9 +3437,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -3412,9 +3452,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -3435,15 +3475,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -3452,9 +3492,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -3471,9 +3511,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -3482,15 +3522,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" @@ -3504,9 +3544,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -3516,7 +3556,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -3795,7 +3834,7 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.9.2", + "rand 0.9.3", "ring", "serde", "thiserror 2.0.18", @@ -3818,7 +3857,7 @@ dependencies = [ "moka", "once_cell", "parking_lot", - "rand 0.9.2", + "rand 0.9.3", "resolv-conf", "serde", "smallvec", @@ -4482,7 +4521,7 @@ dependencies = [ "jsonrpsee-types", "parking_lot", "pin-project", - "rand 0.9.2", + "rand 0.9.3", "rustc-hash", "serde", "serde_json", @@ -4778,6 +4817,17 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.23" @@ -5024,7 +5074,7 @@ dependencies = [ "hashbrown 0.16.1", "metrics", "quanta", - "rand 0.9.2", + "rand 0.9.3", "rand_xoshiro", "sketches-ddsketch", ] @@ -5662,7 +5712,7 @@ dependencies = [ "futures-util", "opentelemetry", "percent-encoding", - "rand 0.9.2", + "rand 0.9.3", "thiserror 2.0.18", ] @@ -6061,7 +6111,7 @@ dependencies = [ "bit-vec", "bitflags 2.10.0", "num-traits", - "rand 0.9.2", + "rand 0.9.3", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -6173,7 +6223,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.3", "ring", "rustc-hash", "rustls", @@ -6222,9 +6272,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -6234,9 +6284,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -6306,7 +6356,7 @@ version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d8b5b858a440a0bc02625b62dd95131b9201aa9f69f411195dd4a7cfb1de3d7" dependencies = [ - "rand 0.9.2", + "rand 0.9.3", "rustversion", ] @@ -6448,6 +6498,26 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "reedline" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2066729dce9fecd28d1c6850a159ee68719130f149b22467c362353e16994e90" +dependencies = [ + "chrono", + "crossterm", + "fd-lock", + "itertools 0.13.0", + "nu-ansi-term", + "serde", + "strip-ansi-escapes", + "strum", + "thiserror 2.0.18", + "unicase", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "ref-cast" version = "1.0.25" @@ -6562,7 +6632,7 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "reth" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "alloy-rpc-types", @@ -6602,7 +6672,7 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6626,7 +6696,7 @@ dependencies = [ [[package]] name = "reth-chain-state" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6637,7 +6707,7 @@ dependencies = [ "metrics", "parking_lot", "pin-project", - "rand 0.9.2", + "rand 0.9.3", "rayon", "reth-chainspec", "reth-errors", @@ -6658,7 +6728,7 @@ dependencies = [ [[package]] name = "reth-chainspec" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6678,7 +6748,7 @@ dependencies = [ [[package]] name = "reth-cli" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-genesis", "clap", @@ -6692,7 +6762,7 @@ dependencies = [ [[package]] name = "reth-cli-commands" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6772,7 +6842,7 @@ dependencies = [ [[package]] name = "reth-cli-runner" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "reth-tasks", "tokio", @@ -6782,14 +6852,14 @@ dependencies = [ [[package]] name = "reth-cli-util" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", "cfg-if", "eyre", "libc", - "rand 0.8.5", + "rand 0.8.6", "reth-fs-util", "secp256k1 0.30.0", "serde", @@ -6800,7 +6870,7 @@ dependencies = [ [[package]] name = "reth-codecs" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6820,7 +6890,7 @@ dependencies = [ [[package]] name = "reth-codecs-derive" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "proc-macro2", "quote", @@ -6830,7 +6900,7 @@ dependencies = [ [[package]] name = "reth-config" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "eyre", "humantime-serde", @@ -6846,7 +6916,7 @@ dependencies = [ [[package]] name = "reth-consensus" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -6859,7 +6929,7 @@ dependencies = [ [[package]] name = "reth-consensus-common" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6871,7 +6941,7 @@ dependencies = [ [[package]] name = "reth-consensus-debug-client" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6897,7 +6967,7 @@ dependencies = [ [[package]] name = "reth-db" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "derive_more", @@ -6924,7 +6994,7 @@ dependencies = [ [[package]] name = "reth-db-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -6953,7 +7023,7 @@ dependencies = [ [[package]] name = "reth-db-common" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -6983,7 +7053,7 @@ dependencies = [ [[package]] name = "reth-db-models" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -6998,7 +7068,7 @@ dependencies = [ [[package]] name = "reth-discv4" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7006,7 +7076,7 @@ dependencies = [ "enr", "itertools 0.14.0", "parking_lot", - "rand 0.8.5", + "rand 0.8.6", "reth-ethereum-forks", "reth-net-banlist", "reth-net-nat", @@ -7023,7 +7093,7 @@ dependencies = [ [[package]] name = "reth-discv5" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7033,7 +7103,7 @@ dependencies = [ "futures", "itertools 0.14.0", "metrics", - "rand 0.9.2", + "rand 0.9.3", "reth-chainspec", "reth-ethereum-forks", "reth-metrics", @@ -7047,7 +7117,7 @@ dependencies = [ [[package]] name = "reth-dns-discovery" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "dashmap", @@ -7071,7 +7141,7 @@ dependencies = [ [[package]] name = "reth-downloaders" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7106,7 +7176,7 @@ dependencies = [ [[package]] name = "reth-e2e-test-utils" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7164,7 +7234,7 @@ dependencies = [ [[package]] name = "reth-ecies" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "aes", "alloy-primitives", @@ -7178,7 +7248,7 @@ dependencies = [ "futures", "hmac", "pin-project", - "rand 0.8.5", + "rand 0.8.6", "reth-network-peers", "secp256k1 0.30.0", "sha2", @@ -7192,7 +7262,7 @@ dependencies = [ [[package]] name = "reth-engine-local" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7215,7 +7285,7 @@ dependencies = [ [[package]] name = "reth-engine-primitives" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7240,7 +7310,7 @@ dependencies = [ [[package]] name = "reth-engine-service" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "futures", "pin-project", @@ -7262,7 +7332,7 @@ dependencies = [ [[package]] name = "reth-engine-tree" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eip7928", @@ -7319,7 +7389,7 @@ dependencies = [ [[package]] name = "reth-engine-util" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -7347,7 +7417,7 @@ dependencies = [ [[package]] name = "reth-era" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7362,7 +7432,7 @@ dependencies = [ [[package]] name = "reth-era-downloader" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "bytes", @@ -7378,7 +7448,7 @@ dependencies = [ [[package]] name = "reth-era-utils" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7400,7 +7470,7 @@ dependencies = [ [[package]] name = "reth-errors" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "reth-consensus", "reth-execution-errors", @@ -7411,7 +7481,7 @@ dependencies = [ [[package]] name = "reth-eth-wire" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-chains", "alloy-primitives", @@ -7439,7 +7509,7 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-chains", "alloy-consensus", @@ -7460,7 +7530,7 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "clap", "eyre", @@ -7483,7 +7553,7 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7499,7 +7569,7 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7517,7 +7587,7 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -7530,7 +7600,7 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7559,7 +7629,7 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7579,7 +7649,7 @@ dependencies = [ [[package]] name = "reth-etl" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "rayon", "reth-db-api", @@ -7589,7 +7659,7 @@ dependencies = [ [[package]] name = "reth-evm" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7613,7 +7683,7 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7635,7 +7705,7 @@ dependencies = [ [[package]] name = "reth-execution-errors" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-evm", "alloy-primitives", @@ -7648,7 +7718,7 @@ dependencies = [ [[package]] name = "reth-execution-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7666,7 +7736,7 @@ dependencies = [ [[package]] name = "reth-exex" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7704,7 +7774,7 @@ dependencies = [ [[package]] name = "reth-exex-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7718,7 +7788,7 @@ dependencies = [ [[package]] name = "reth-fs-util" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "serde", "serde_json", @@ -7728,7 +7798,7 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7756,7 +7826,7 @@ dependencies = [ [[package]] name = "reth-ipc" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "bytes", "futures", @@ -7776,7 +7846,7 @@ dependencies = [ [[package]] name = "reth-libmdbx" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "bitflags 2.10.0", "byteorder", @@ -7792,7 +7862,7 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "bindgen", "cc", @@ -7801,7 +7871,7 @@ dependencies = [ [[package]] name = "reth-metrics" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "futures", "metrics", @@ -7813,7 +7883,7 @@ dependencies = [ [[package]] name = "reth-net-banlist" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "ipnet", @@ -7822,7 +7892,7 @@ dependencies = [ [[package]] name = "reth-net-nat" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "futures-util", "if-addrs", @@ -7836,7 +7906,7 @@ dependencies = [ [[package]] name = "reth-network" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7852,8 +7922,8 @@ dependencies = [ "metrics", "parking_lot", "pin-project", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.3", "rayon", "reth-chainspec", "reth-consensus", @@ -7893,7 +7963,7 @@ dependencies = [ [[package]] name = "reth-network-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7918,7 +7988,7 @@ dependencies = [ [[package]] name = "reth-network-p2p" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7941,7 +8011,7 @@ dependencies = [ [[package]] name = "reth-network-peers" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7956,7 +8026,7 @@ dependencies = [ [[package]] name = "reth-network-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -7970,7 +8040,7 @@ dependencies = [ [[package]] name = "reth-nippy-jar" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "anyhow", "bincode 1.3.3", @@ -7987,7 +8057,7 @@ dependencies = [ [[package]] name = "reth-node-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-rpc-types-engine", "eyre", @@ -8011,7 +8081,7 @@ dependencies = [ [[package]] name = "reth-node-builder" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8080,7 +8150,7 @@ dependencies = [ [[package]] name = "reth-node-core" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8093,7 +8163,7 @@ dependencies = [ "futures", "humantime", "ipnet", - "rand 0.9.2", + "rand 0.9.3", "reth-chainspec", "reth-cli-util", "reth-config", @@ -8135,7 +8205,7 @@ dependencies = [ [[package]] name = "reth-node-ethereum" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-network", @@ -8173,7 +8243,7 @@ dependencies = [ [[package]] name = "reth-node-ethstats" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8197,7 +8267,7 @@ dependencies = [ [[package]] name = "reth-node-events" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8221,7 +8291,7 @@ dependencies = [ [[package]] name = "reth-node-metrics" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "bytes", "eyre", @@ -8245,7 +8315,7 @@ dependencies = [ [[package]] name = "reth-node-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "reth-chainspec", "reth-db-api", @@ -8257,7 +8327,7 @@ dependencies = [ [[package]] name = "reth-payload-builder" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8278,7 +8348,7 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "pin-project", "reth-payload-primitives", @@ -8290,7 +8360,7 @@ dependencies = [ [[package]] name = "reth-payload-primitives" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8313,7 +8383,7 @@ dependencies = [ [[package]] name = "reth-payload-validator" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -8323,7 +8393,7 @@ dependencies = [ [[package]] name = "reth-primitives" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8337,7 +8407,7 @@ dependencies = [ [[package]] name = "reth-primitives-traits" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8371,7 +8441,7 @@ dependencies = [ [[package]] name = "reth-provider" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8416,7 +8486,7 @@ dependencies = [ [[package]] name = "reth-prune" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8445,7 +8515,7 @@ dependencies = [ [[package]] name = "reth-prune-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "arbitrary", @@ -8461,7 +8531,7 @@ dependencies = [ [[package]] name = "reth-revm" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "reth-primitives-traits", @@ -8474,7 +8544,7 @@ dependencies = [ [[package]] name = "reth-rpc" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8551,7 +8621,7 @@ dependencies = [ [[package]] name = "reth-rpc-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eip7928", "alloy-eips", @@ -8581,7 +8651,7 @@ dependencies = [ [[package]] name = "reth-rpc-builder" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-network", "alloy-provider", @@ -8622,7 +8692,7 @@ dependencies = [ [[package]] name = "reth-rpc-convert" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-evm", @@ -8643,7 +8713,7 @@ dependencies = [ [[package]] name = "reth-rpc-engine-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8673,7 +8743,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8717,7 +8787,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8734,7 +8804,7 @@ dependencies = [ "jsonrpsee-core", "jsonrpsee-types", "metrics", - "rand 0.9.2", + "rand 0.9.3", "reqwest", "reth-chain-state", "reth-chainspec", @@ -8765,7 +8835,7 @@ dependencies = [ [[package]] name = "reth-rpc-layer" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-rpc-types-engine", "http", @@ -8779,7 +8849,7 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8795,7 +8865,7 @@ dependencies = [ [[package]] name = "reth-stages" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8845,7 +8915,7 @@ dependencies = [ [[package]] name = "reth-stages-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8872,7 +8942,7 @@ dependencies = [ [[package]] name = "reth-stages-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "arbitrary", @@ -8886,7 +8956,7 @@ dependencies = [ [[package]] name = "reth-static-file" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "parking_lot", @@ -8906,7 +8976,7 @@ dependencies = [ [[package]] name = "reth-static-file-types" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "clap", @@ -8921,7 +8991,7 @@ dependencies = [ [[package]] name = "reth-storage-api" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8945,7 +9015,7 @@ dependencies = [ [[package]] name = "reth-storage-errors" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8962,7 +9032,7 @@ dependencies = [ [[package]] name = "reth-tasks" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "auto_impl", "dyn-clone", @@ -8980,14 +9050,14 @@ dependencies = [ [[package]] name = "reth-testing-utils" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", "alloy-primitives", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.3", "reth-ethereum-primitives", "reth-primitives-traits", "secp256k1 0.30.0", @@ -8996,7 +9066,7 @@ dependencies = [ [[package]] name = "reth-tokio-util" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "tokio", "tokio-stream", @@ -9006,7 +9076,7 @@ dependencies = [ [[package]] name = "reth-tracing" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "clap", "eyre", @@ -9023,7 +9093,7 @@ dependencies = [ [[package]] name = "reth-tracing-otlp" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "clap", "eyre", @@ -9041,7 +9111,7 @@ dependencies = [ [[package]] name = "reth-transaction-pool" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9055,7 +9125,7 @@ dependencies = [ "parking_lot", "paste", "pin-project", - "rand 0.9.2", + "rand 0.9.3", "reth-chain-state", "reth-chainspec", "reth-eth-wire-types", @@ -9085,7 +9155,7 @@ dependencies = [ [[package]] name = "reth-trie" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9111,7 +9181,7 @@ dependencies = [ [[package]] name = "reth-trie-common" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9138,7 +9208,7 @@ dependencies = [ [[package]] name = "reth-trie-db" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "metrics", @@ -9158,7 +9228,7 @@ dependencies = [ [[package]] name = "reth-trie-parallel" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9183,7 +9253,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9202,7 +9272,7 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +source = "git+https://github.com/camembera/reth?branch=pog%2Fprovenance-callback#ab0c215ee7276dab1f9cc944258b530a7cef466a" dependencies = [ "zstd", ] @@ -9550,8 +9620,8 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.3", "rlp", "ruint-macro", "serde_core", @@ -9565,13 +9635,27 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags 2.10.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" dependencies = [ - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -9806,7 +9890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", + "rand 0.8.6", "secp256k1-sys 0.10.1", "serde", ] @@ -9818,7 +9902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" dependencies = [ "bitcoin_hashes", - "rand 0.9.2", + "rand 0.9.3", "secp256k1-sys 0.11.0", ] @@ -10246,7 +10330,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.8.5", + "rand 0.8.6", "sha1", ] @@ -10272,6 +10356,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.11.1" @@ -11087,7 +11180,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.2", + "rand 0.9.3", "rustls", "rustls-pki-types", "sha1", @@ -11106,7 +11199,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.2", + "rand 0.9.3", "sha1", "thiserror 2.0.18", "utf-8", @@ -11353,6 +11446,15 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 21942def..256e4b82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,71 +15,90 @@ alloy-rlp = "0.3.13" alloy-rpc-types = "1.6.3" alloy-rpc-types-eth = "1.6.3" alloy-serde = "1.6.3" +alloy-signer = "1.6.3" alloy-signer-local = "1.6.3" alloy-sol-macro = "1.5.6" alloy-sol-types = "1.5.6" bytes = "1.10.1" clap = { version = "4.5.40", features = ["derive"] } derive_more = "2.0.1" +dirs = "6.0.0" eyre = "0.6.12" +libc = "0.2.177" +reedline = "0.47" sha2 = "0.10" # rpc -jsonrpsee = "0.26.0" +jsonrpsee = { version = "0.26.0", features = ["http-client", "ws-client"] } jsonrpsee-core = { version = "0.26.0", features = ["server"] } jsonrpsee-proc-macros = "0.26.0" async-trait = "0.1.88" +futures = "0.3.32" modular-bitfield = "0.13.1" -reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-cli-commands = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-codecs = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-consensus-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-engine-local = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-engine-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-engine-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-network-peers = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-validator = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-convert = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-engine-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-storage-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } +# RUSTSEC-2026-0097: use >=0.8.6 on the 0.8 release line. +rand = "0.8.6" +reth = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-basic-payload-builder = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-chainspec = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-cli = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-cli-commands = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-cli-runner = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-cli-util = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-codecs = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-consensus-common = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-db = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-db-api = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-engine-local = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-engine-primitives = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-errors = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-eth-wire-types = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-ethereum-cli = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-ethereum-engine-primitives = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-ethereum-payload-builder = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-ethereum-primitives = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-evm = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-evm-ethereum = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-metrics = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-network = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-network-api = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-network-peers = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-network-types = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-node-api = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-node-builder = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-node-core = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-node-ethereum = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-payload-primitives = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-payload-validator = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-primitives-traits = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc-convert = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc-engine-api = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc-eth-api = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc-eth-types = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc-server-types = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-storage-api = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-transaction-pool = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +rusqlite = { version = "0.32", features = ["bundled"] } serde = { version = "1.0", features = ["derive"], default-features = false } serde_json = "1.0" thiserror = "2.0" -tokio = "1.46.0" +tokio = { version = "1.46.0", features = ["macros", "rt-multi-thread", "net", "io-util"] } tracing = "0.1.41" +tracing-subscriber = { version = "0.3", default-features = false, features = ["registry"] } [dev-dependencies] alloy-provider = "1.6.3" alloy-rpc-client = "1.6.3" alloy-rpc-types-trace = "1.6.3" eyre = "0.6.12" -reth-e2e-test-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-trie-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } +jsonrpsee = { version = "0.26.0", features = ["server"] } +reth-e2e-test-utils = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-rpc-builder = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } +reth-trie-common = { git = "https://github.com/camembera/reth", branch = "pog/provenance-callback" } revm-inspectors = "0.34.2" +serde_json = "1.0" +tempfile = "3" test-fuzz = "7" [build-dependencies] @@ -110,7 +129,26 @@ opt-level = 3 lto = "thin" [package.metadata.cargo-machete] -ignored = ["modular-bitfield"] +# cargo-machete misses macro/build.rs/test-only uses; keep explicit allowlist in sync when deps change. +ignored = [ + "alloy-provider", + "alloy-rpc-client", + "alloy-signer", + "futures", + "modular-bitfield", + "rand", + "reth-eth-wire-types", + "reth-metrics", + "reth-network", + "reth-network-api", + "reth-network-types", + "reth-rpc-builder", + "rusqlite", + "test-fuzz", + "tracing-subscriber", + "vergen", + "vergen-git2", +] # [patch."https://github.com/paradigmxyz/reth"] # reth = { path = "../reth/bin/reth" } diff --git a/src/berachain_cli.rs b/src/berachain_cli.rs new file mode 100644 index 00000000..ee2cdc68 --- /dev/null +++ b/src/berachain_cli.rs @@ -0,0 +1,58 @@ +//! Berachain-specific CLI subcommands (extension to reth Ethereum CLI). + +use clap::Subcommand; +use reth_cli_runner::CliRunner; +use reth_ethereum_cli::app::ExtendedCommand; + +#[derive(Debug, Subcommand)] +pub enum BerachainSubcommands { + /// JSON-RPC console over IPC, HTTP, or WebSocket. + Console(crate::console::ConsoleCommand), +} + +impl ExtendedCommand for BerachainSubcommands { + fn execute(self, runner: CliRunner) -> eyre::Result<()> { + match self { + Self::Console(cmd) => cmd.run(runner), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::chainspec::BerachainChainSpecParser; + use clap::Parser; + use reth_cli_commands::node::NoArgs; + use reth_ethereum_cli::interface::{Cli, Commands}; + use reth_rpc_server_types::DefaultRpcModuleValidator; + + #[test] + fn parses_console_subcommand() { + let err = Cli::< + BerachainChainSpecParser, + NoArgs, + DefaultRpcModuleValidator, + BerachainSubcommands, + >::try_parse_from(["bera-reth", "console", "--help"]) + .unwrap_err(); + assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); + } + + #[test] + fn ext_console_variant_reachable() { + let cli = Cli::< + BerachainChainSpecParser, + NoArgs, + DefaultRpcModuleValidator, + BerachainSubcommands, + >::try_parse_from(["bera-reth", "console", "--exec", "eth_blockNumber"]) + .unwrap(); + match cli.command { + Commands::Ext(BerachainSubcommands::Console(ref c)) => { + assert_eq!(c.exec.as_deref(), Some("eth_blockNumber")); + } + _ => panic!("expected console ext"), + } + } +} diff --git a/src/chainspec/mod.rs b/src/chainspec/mod.rs index 8322691f..b5523f3c 100644 --- a/src/chainspec/mod.rs +++ b/src/chainspec/mod.rs @@ -127,8 +127,8 @@ impl BerachainChainSpec { // We filter out TTD-based forks w/o a pre-known block since those do not show up in // the fork filter. Some(match condition { - ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } => ForkFilterKey::Block(block), + ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } => ForkFilterKey::Block(block), ForkCondition::Timestamp(time) => ForkFilterKey::Time(time), _ => return None, }) @@ -160,8 +160,8 @@ impl BerachainChainSpec { for (_, cond) in self.inner.hardforks.forks_iter() { // handle block based forks and the sepolia merge netsplit block edge case (TTD // ForkCondition with Some(block)) - if let ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } = cond + if let ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } = cond { if head.number >= block { // skip duplicated hardforks: hardforks enabled at genesis block @@ -573,8 +573,8 @@ impl From for BerachainChainSpec { } // Validate Prague3 ordering if configured (Prague3 must come at or after Prague2) - if let Some(prague3_config) = prague3_config_opt.as_ref() && - prague3_config.time < prague2_config.time + if let Some(prague3_config) = prague3_config_opt.as_ref() + && prague3_config.time < prague2_config.time { panic!( "Prague3 hardfork must activate at or after Prague2 hardfork. Prague2 time: {}, Prague3 time: {}.", diff --git a/src/consensus/mod.rs b/src/consensus/mod.rs index a4ec9704..2f155998 100644 --- a/src/consensus/mod.rs +++ b/src/consensus/mod.rs @@ -135,8 +135,8 @@ impl FullConsensus for BerachainBeaconConsensus { for receipt in &result.receipts { for log in &receipt.logs { // Check if this is a Transfer event (first topic is the event signature) - if log.topics().first() == Some(&TRANSFER_EVENT_SIGNATURE) && - log.topics().len() >= 3 + if log.topics().first() == Some(&TRANSFER_EVENT_SIGNATURE) + && log.topics().len() >= 3 { // Transfer event has indexed from (topics[1]) and to (topics[2]) addresses let from_addr = Address::from_word(log.topics()[1]); @@ -144,8 +144,8 @@ impl FullConsensus for BerachainBeaconConsensus { // Check if BEX vault is involved in the transfer (block all BEX vault // transfers) - if let Some(bex_vault) = bex_vault_address && - (from_addr == bex_vault || to_addr == bex_vault) + if let Some(bex_vault) = bex_vault_address + && (from_addr == bex_vault || to_addr == bex_vault) { return Err(ConsensusError::Other( BerachainExecutionError::Prague3BexVaultTransfer { @@ -197,8 +197,8 @@ impl FullConsensus for BerachainBeaconConsensus { for log in &receipt.logs { // Check if this log is from the BEX vault and is an InternalBalanceChanged // event - if log.address == bex_vault_address && - log.topics().first() == Some(&INTERNAL_BALANCE_CHANGED_SIGNATURE) + if log.address == bex_vault_address + && log.topics().first() == Some(&INTERNAL_BALANCE_CHANGED_SIGNATURE) { return Err(ConsensusError::Other( BerachainExecutionError::Prague3BexVaultEvent { diff --git a/src/console/cli.rs b/src/console/cli.rs new file mode 100644 index 00000000..dc961335 --- /dev/null +++ b/src/console/cli.rs @@ -0,0 +1,60 @@ +use clap::Args; +use reth_cli_runner::CliRunner; + +/// JSON-RPC console over IPC. +#[derive(Debug, Clone, Args)] +pub struct ConsoleCommand { + /// IPC path. If omitted, uses the platform default datadir with `reth.ipc`. + #[arg(value_name = "ENDPOINT")] + pub endpoint: Option, + + /// Run a single command and print raw JSON (implies raw output; no prompts). + #[arg(long = "exec")] + pub exec: Option, + + /// In REPL mode, print raw JSON instead of tables and annotations. + #[arg(long)] + pub raw: bool, +} + +impl ConsoleCommand { + pub fn run(self, runner: CliRunner) -> eyre::Result<()> { + runner.block_on(super::run::run_console(self)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use clap::Parser; + + #[derive(clap::Parser)] + #[command(name = "bera-reth")] + struct Top { + #[command(subcommand)] + sub: Sub, + } + + #[derive(clap::Subcommand)] + enum Sub { + Console(ConsoleCommand), + } + + #[test] + fn parses_exec_and_raw() { + let Top { sub: Sub::Console(c) } = + Top::try_parse_from(["bera-reth", "console", "--exec", "eth.blockNumber", "--raw"]) + .unwrap(); + assert_eq!(c.exec.as_deref(), Some("eth.blockNumber")); + assert!(c.raw); + assert!(c.endpoint.is_none()); + } + + #[test] + fn parses_positional_endpoint() { + let Top { sub: Sub::Console(c) } = + Top::try_parse_from(["bera-reth", "console", "/tmp/reth.ipc"]).unwrap(); + assert_eq!(c.endpoint.as_deref(), Some("/tmp/reth.ipc")); + assert!(!c.raw); + } +} diff --git a/src/console/command.rs b/src/console/command.rs new file mode 100644 index 00000000..084b78fe --- /dev/null +++ b/src/console/command.rs @@ -0,0 +1,307 @@ +use eyre::{Result, eyre}; +use serde_json::Value; + +#[derive(Debug, Clone, PartialEq)] +pub enum InputCommand { + Empty, + Help, + Exit, + Query(String), + Rpc { + method: String, + params: Option, + }, + RpcWithQuery { + method: String, + params: Option, + query: String, + }, + /// Single token treated as a method name (`eth.blockNumber` → `eth_blockNumber`). + MethodToken(String), +} + +pub fn parse_input(line: &str) -> Result { + let line = line.trim(); + if line.is_empty() { + return Ok(InputCommand::Empty); + } + if line == "help" || line == "?" { + return Ok(InputCommand::Help); + } + if line == "exit" || line == "quit" { + return Ok(InputCommand::Exit); + } + if line.starts_with('.') { + return Ok(InputCommand::Query(line.to_owned())); + } + if let Some((rpc_part, query)) = split_rpc_query_tail(line) { + let (method, params_raw) = split_method_and_params(rpc_part)?; + let params = parse_params(params_raw)?; + return Ok(InputCommand::RpcWithQuery { method, params, query }); + } + if looks_like_implicit_rpc(line) { + return parse_rpc(line); + } + Ok(InputCommand::MethodToken(line.to_owned())) +} + +fn split_rpc_query_tail(line: &str) -> Option<(&str, String)> { + if line.contains(char::is_whitespace) || line.contains('(') { + return None; + } + + let query_start = if let Some(p1) = line.find('.') { + let before_dot = &line[..p1]; + if before_dot.contains('_') { + // Underscore-style method (e.g. admin_peers): first '.' or '[' is query start. + let first_bracket = line.find('['); + match first_bracket { + Some(b) if b < p1 => Some(b), + _ => Some(p1), + } + } else { + // Dot-style method (e.g. admin.peers): consume two segments, remainder is query. + let after_p1 = p1 + 1; + let seg2_len = line[after_p1..] + .find(|c: char| ['.', '['].contains(&c)) + .unwrap_or(line.len() - after_p1); + let seg2_end = after_p1 + seg2_len; + if seg2_end < line.len() { Some(seg2_end) } else { None } + } + } else { + line.find('[') + }?; + + let rpc_part = &line[..query_start]; + let raw_tail = &line[query_start..]; + if raw_tail.is_empty() { + return None; + } + let query = + if raw_tail.starts_with('[') { format!(".{raw_tail}") } else { raw_tail.to_owned() }; + Some((rpc_part, query)) +} + +fn parse_rpc(rest: &str) -> Result { + let rest = rest.trim(); + if rest.is_empty() { + return Err(eyre!("usage: [json_params]")); + } + let (method, params_raw) = split_method_and_params(rest)?; + let parsed_params = parse_params(params_raw)?; + Ok(InputCommand::Rpc { method, params: parsed_params }) +} + +fn looks_like_implicit_rpc(line: &str) -> bool { + // Accept direct method calls like: + // - eth_getBalance ["0x...", "latest"] + // - eth.getBalance ["0x...", "latest"] + // Single-token `eth.blockNumber`-style input is handled as MethodToken. + line.contains(char::is_whitespace) + || (line.contains('(') && line.ends_with(')')) + || (line.contains('_') && !line.contains(' ')) +} + +fn split_method_and_params(input: &str) -> Result<(String, Option<&str>)> { + let input = input.trim(); + if let Some(paren_start) = input.find('(') { + let method = input[..paren_start].trim(); + if method.is_empty() { + return Err(eyre!("missing method name")); + } + if !input.ends_with(')') { + return Err(eyre!("unbalanced parentheses in method call")); + } + let inner = &input[paren_start + 1..input.len() - 1]; + let params = if inner.trim().is_empty() { None } else { Some(inner.trim()) }; + return Ok((method.to_owned(), params)); + } + + let mut split = input.splitn(2, char::is_whitespace); + let method = split.next().unwrap_or_default().trim(); + if method.is_empty() { + return Err(eyre!("missing method name")); + } + let params = split.next().map(str::trim).filter(|s| !s.is_empty()); + Ok((method.to_owned(), params)) +} + +fn parse_params(params_raw: Option<&str>) -> Result> { + let Some(raw) = params_raw else { + return Ok(None); + }; + let mut s = raw.trim(); + while s.starts_with('(') && s.ends_with(')') && s.len() >= 2 { + s = s[1..s.len() - 1].trim(); + } + if s.is_empty() { + return Ok(None); + } + + // If wrapped as a JSON array, use it directly as RPC positional params. + if s.starts_with('[') && s.ends_with(']') { + return Ok(Some(serde_json::from_str::(s)?)); + } + // If wrapped as a JSON object, pass as named params. + if s.starts_with('{') && s.ends_with('}') { + return Ok(Some(serde_json::from_str::(s)?)); + } + + // Function-style "a, b, c" => parse as positional params. + let array_form = format!("[{s}]"); + if let Ok(v) = serde_json::from_str::(&array_form) { + return Ok(Some(v)); + } + + // Single scalar JSON value fallback. + if let Ok(v) = serde_json::from_str::(s) { + return Ok(Some(Value::Array(vec![v]))); + } + + Err(eyre!("unable to parse params; use JSON values, e.g. [\"0x...\", \"latest\"]")) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn parses_rpc_with_params() { + let cmd = parse_input(r#"eth_getBlockByNumber ["latest", false]"#).unwrap(); + assert_eq!( + cmd, + InputCommand::Rpc { + method: "eth_getBlockByNumber".to_owned(), + params: Some(json!(["latest", false])), + } + ); + } + + #[test] + fn parses_query() { + let cmd = parse_input(".count").unwrap(); + assert_eq!(cmd, InputCommand::Query(".count".to_owned())); + } + + #[test] + fn parses_implicit_rpc_with_params() { + let cmd = parse_input(r#"eth.getBalance ["0xabc", "latest"]"#).unwrap(); + assert_eq!( + cmd, + InputCommand::Rpc { + method: "eth.getBalance".to_owned(), + params: Some(json!(["0xabc", "latest"])), + } + ); + } + + #[test] + fn parses_parenthesized_call_with_array() { + let cmd = parse_input(r#"eth.getBalance(["0xabc", "latest"])"#).unwrap(); + assert_eq!( + cmd, + InputCommand::Rpc { + method: "eth.getBalance".to_owned(), + params: Some(json!(["0xabc", "latest"])), + } + ); + } + + #[test] + fn parses_parenthesized_call_without_array() { + let cmd = parse_input(r#"eth.getBalance("0xabc", "latest")"#).unwrap(); + assert_eq!( + cmd, + InputCommand::Rpc { + method: "eth.getBalance".to_owned(), + params: Some(json!(["0xabc", "latest"])), + } + ); + } + + #[test] + fn parses_empty_as_empty_command() { + assert_eq!(parse_input(" ").unwrap(), InputCommand::Empty); + } + + #[test] + fn keeps_dot_method_token_when_no_params() { + assert_eq!( + parse_input("eth.blockNumber").unwrap(), + InputCommand::MethodToken("eth.blockNumber".to_owned()) + ); + } + + #[test] + fn errors_on_unbalanced_parentheses() { + let err = parse_input(r#"eth.getBalance("0xabc", "latest""#).unwrap_err(); + assert!(err.to_string().contains("unbalanced parentheses")); + } + + #[test] + fn errors_on_invalid_params() { + let err = parse_input(r#"eth_getBalance [broken"#).unwrap_err(); + assert!(err.to_string().contains("unable to parse params")); + } + + #[test] + fn chained_dot_count() { + let cmd = parse_input("admin.peers.count").unwrap(); + assert_eq!( + cmd, + InputCommand::RpcWithQuery { + method: "admin.peers".to_owned(), + params: None, + query: ".count".to_owned(), + } + ); + } + + #[test] + fn chained_bracket_index_and_field() { + let cmd = parse_input("admin.peers[0].caps").unwrap(); + assert_eq!( + cmd, + InputCommand::RpcWithQuery { + method: "admin.peers".to_owned(), + params: None, + query: ".[0].caps".to_owned(), + } + ); + } + + #[test] + fn chained_bracket_only() { + let cmd = parse_input("admin.peers[0]").unwrap(); + assert_eq!( + cmd, + InputCommand::RpcWithQuery { + method: "admin.peers".to_owned(), + params: None, + query: ".[0]".to_owned(), + } + ); + } + + #[test] + fn chained_underscore_style() { + let cmd = parse_input("admin_peers.count").unwrap(); + assert_eq!( + cmd, + InputCommand::RpcWithQuery { + method: "admin_peers".to_owned(), + params: None, + query: ".count".to_owned(), + } + ); + } + + #[test] + fn no_chain_on_plain_method_token() { + assert_eq!( + parse_input("admin.peers").unwrap(), + InputCommand::MethodToken("admin.peers".to_owned()) + ); + } +} diff --git a/src/console/endpoint.rs b/src/console/endpoint.rs new file mode 100644 index 00000000..936b3361 --- /dev/null +++ b/src/console/endpoint.rs @@ -0,0 +1,75 @@ +use eyre::{Result, bail}; +use std::path::PathBuf; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Transport { + Ipc, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ResolvedEndpoint { + pub raw: String, + pub transport: Transport, +} + +const DEFAULT_IPC_FILENAME: &str = "reth.ipc"; + +pub fn default_datadir() -> PathBuf { + if cfg!(target_os = "macos") + && let Some(home) = dirs::home_dir() + { + return home.join("Library").join("Application Support").join("reth"); + } + dirs::data_dir().unwrap_or_else(|| PathBuf::from(".")).join("reth") +} + +pub fn resolve_endpoint(endpoint: Option<&str>) -> Result { + let raw = match endpoint { + Some(e) => e.to_owned(), + None => default_datadir().join(DEFAULT_IPC_FILENAME).to_string_lossy().into_owned(), + }; + let transport = detect_transport(&raw)?; + Ok(ResolvedEndpoint { raw, transport }) +} + +fn detect_transport(endpoint: &str) -> Result { + let lower = endpoint.to_ascii_lowercase(); + if lower.contains("://") { + bail!("unsupported endpoint scheme in {endpoint:?}"); + } + Ok(Transport::Ipc) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn defaults_to_ipc_path() { + let got = resolve_endpoint(None).unwrap(); + assert_eq!(got.transport, Transport::Ipc); + assert!(got.raw.ends_with("reth.ipc")); + } + + #[test] + fn rejects_unknown_scheme() { + let err = resolve_endpoint(Some("ftp://example.test")).unwrap_err(); + assert!(err.to_string().contains("unsupported endpoint scheme")); + } + + #[test] + fn windows_named_pipe_path_is_ipc() { + let raw = r"\\.\pipe\reth.ipc"; + let got = resolve_endpoint(Some(raw)).unwrap(); + assert_eq!(got.transport, Transport::Ipc); + assert_eq!(got.raw, raw); + } + + #[test] + fn relative_path_with_colons_is_ipc() { + let raw = "relative:with:segments/reth.ipc"; + let got = resolve_endpoint(Some(raw)).unwrap(); + assert_eq!(got.transport, Transport::Ipc); + assert_eq!(got.raw, raw); + } +} diff --git a/src/console/engine.rs b/src/console/engine.rs new file mode 100644 index 00000000..3156d830 --- /dev/null +++ b/src/console/engine.rs @@ -0,0 +1,125 @@ +use super::{ + command::{InputCommand, parse_input}, + query::apply_query, + rpc::RpcClient, +}; +use eyre::{Result, eyre}; +use serde_json::Value; + +pub enum EvalOutcome { + Noop, + Exit, + Help, + Value(Value), +} + +pub async fn evaluate_line( + rpc: &RpcClient, + line: &str, + last_rpc_result: &mut Option, +) -> Result { + match parse_input(line)? { + InputCommand::Empty => Ok(EvalOutcome::Noop), + InputCommand::Exit => Ok(EvalOutcome::Exit), + InputCommand::Help => Ok(EvalOutcome::Help), + InputCommand::Query(expr) => { + let next = apply_query_to_last_rpc(&expr, last_rpc_result)?; + Ok(EvalOutcome::Value(next)) + } + InputCommand::Rpc { method, params } => { + let normalized_method = normalize_rpc_method(&method); + let value = rpc.request_value(&normalized_method, params).await?; + *last_rpc_result = Some(value.clone()); + Ok(EvalOutcome::Value(value)) + } + InputCommand::RpcWithQuery { method, params, query } => { + let normalized_method = normalize_rpc_method(&method); + let value = rpc.request_value(&normalized_method, params).await?; + *last_rpc_result = Some(value.clone()); + let result = apply_query(&query, &value)?; + Ok(EvalOutcome::Value(result)) + } + InputCommand::MethodToken(token) => { + if is_remove_all_peers_token(token.as_str()) { + return run_remove_all_peers(rpc, last_rpc_result).await; + } + let method = normalize_rpc_method(&token); + let value = rpc.request_value(&method, None).await?; + *last_rpc_result = Some(value.clone()); + Ok(EvalOutcome::Value(value)) + } + } +} + +fn is_remove_all_peers_token(s: &str) -> bool { + matches!(s, "removeAllPeers" | "admin.removeAllPeers") +} + +async fn run_remove_all_peers( + rpc: &RpcClient, + last_rpc_result: &mut Option, +) -> Result { + let peers = rpc.request_value("admin_peers", None).await?; + let arr = peers.as_array().ok_or_else(|| eyre!("admin.peers did not return an array"))?; + let total = arr.len() as u64; + let mut removed = 0u64; + let mut failed = 0u64; + for peer in arr { + let enode = peer + .get("enode") + .and_then(Value::as_str) + .ok_or_else(|| eyre!("peer entry missing enode"))?; + match rpc.request_value("admin_removePeer", Some(serde_json::json!([enode]))).await { + Ok(Value::Bool(true)) => removed += 1, + Ok(other) => { + eprintln!("admin.removePeer({enode}): unexpected response: {other}"); + failed += 1; + } + Err(err) => { + eprintln!("admin.removePeer({enode}): {err}"); + failed += 1; + } + } + } + *last_rpc_result = Some(peers.clone()); + eprintln!("Removed {removed}/{total} peer(s)."); + Ok(EvalOutcome::Value(serde_json::json!({ + "removed": removed, + "failed": failed, + "total": total + }))) +} + +fn apply_query_to_last_rpc(expr: &str, last_rpc_result: &Option) -> Result { + let value = + last_rpc_result.as_ref().ok_or_else(|| eyre!("no last rpc result available for query"))?; + apply_query(expr, value) +} + +fn normalize_rpc_method(method: &str) -> String { + method.replace('.', "_") +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn normalizes_rpc_methods() { + assert_eq!(normalize_rpc_method("eth.getBalance"), "eth_getBalance"); + } + + #[test] + fn query_without_last_result_errors() { + let err = apply_query_to_last_rpc(".count", &None).unwrap_err(); + assert!(err.to_string().contains("no last rpc result available for query")); + } + + #[test] + fn apply_query_on_array_returns_count() { + let peers = json!([{"id": "a"}, {"id": "b"}]); + let count = apply_query(".count", &peers).unwrap(); + assert_eq!(count, json!(2)); + } +} diff --git a/src/console/exec.rs b/src/console/exec.rs new file mode 100644 index 00000000..fb7ab3fe --- /dev/null +++ b/src/console/exec.rs @@ -0,0 +1,29 @@ +use super::{ + engine::{EvalOutcome, evaluate_line}, + rpc::RpcClient, +}; +use eyre::Result; +use serde_json::Value; + +pub async fn run_exec(rpc: &RpcClient, script: &str) -> Result<()> { + let mut last = None; + match evaluate_line(rpc, script, &mut last).await? { + EvalOutcome::Value(value) => print_raw_json(&value), + EvalOutcome::Help => print_help(), + EvalOutcome::Noop | EvalOutcome::Exit => {} + } + Ok(()) +} + +fn print_raw_json(value: &Value) { + println!("{}", serde_json::to_string(value).unwrap_or_else(|_| value.to_string())); +} + +fn print_help() { + println!("Usage:"); + println!( + " [json_params] (RPC call; dots become underscores, e.g. eth.blockNumber)" + ); + println!(" .count | .len | .first | .last | .[0] | .[0].field | .map(.field)"); + println!("Destructive: removeAllPeers | admin.removeAllPeers (batch admin.removePeer)"); +} diff --git a/src/console/mod.rs b/src/console/mod.rs new file mode 100644 index 00000000..e81a4dfc --- /dev/null +++ b/src/console/mod.rs @@ -0,0 +1,16 @@ +//! Operator JSON-RPC console (merged from reth-console). + +mod cli; +mod command; +mod endpoint; +mod engine; +mod exec; +mod output; +mod query; +mod repl; +mod rpc; +/// Method suffix tables for tab-completing `namespace.method` in the REPL. +mod rpc_completion; +mod run; + +pub use cli::ConsoleCommand; diff --git a/src/console/output.rs b/src/console/output.rs new file mode 100644 index 00000000..5130ea01 --- /dev/null +++ b/src/console/output.rs @@ -0,0 +1,616 @@ +use serde_json::Value; + +const DEFAULT_NATIVE_SYMBOL: &str = "ETH"; + +/// Berachain mainnet (80094) and bepolia testnet (80069) chain IDs. +pub(crate) const BERACHAIN_CHAIN_IDS: &[u64] = &[80_069, 80_094]; + +/// ~0.001 native tokens in wei — below this, unlikely to be a balance worth annotating. +const WEI_HEURISTIC_MIN: u128 = 1_000_000_000_000_000; +/// ~10 billion native tokens in wei — above this, not a plausible balance. +const WEI_HEURISTIC_MAX: u128 = 10_000_000_000_000_000_000_000_000_000; + +pub(crate) fn hex_or_decimal_to_u64(value: &Value) -> Option { + match value { + Value::String(s) => { + if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) { + u64::from_str_radix(hex, 16).ok() + } else { + s.parse::().ok() + } + } + Value::Number(n) => n.as_u64(), + _ => None, + } +} + +/// First `max_chars` Unicode scalars (never splits a codepoint). +fn chars_prefix(s: &str, max_chars: usize) -> &str { + if max_chars == 0 { + return ""; + } + let mut end_byte = 0usize; + let mut iter = s.char_indices(); + for _ in 0..max_chars { + match iter.next() { + Some((i, ch)) => end_byte = i + ch.len_utf8(), + None => return s, + } + } + &s[..end_byte] +} + +/// `prefix..suffix` with lengths in characters; returns `s` unchanged if it fits. +fn ellipsis_char_ends(s: &str, prefix_chars: usize, suffix_chars: usize) -> String { + let n = s.chars().count(); + if n <= prefix_chars + suffix_chars { + return s.to_string(); + } + let prefix: String = s.chars().take(prefix_chars).collect(); + let suffix: String = s.chars().skip(n - suffix_chars).collect(); + format!("{prefix}..{suffix}") +} + +pub fn print_value_for_chain(value: &Value, chain_id: Option) { + print_value_with_symbol(value, native_symbol_for_chain_id(chain_id), false); +} + +pub fn print_value_for_chain_raw(value: &Value, chain_id: Option, raw: bool) { + if raw { + println!("{}", pretty(value)); + } else { + print_value_for_chain(value, chain_id); + } +} + +pub fn native_symbol_for_chain_id(chain_id: Option) -> &'static str { + match chain_id { + Some(id) if BERACHAIN_CHAIN_IDS.contains(&id) => "BERA", + _ => DEFAULT_NATIVE_SYMBOL, + } +} + +fn print_value_with_symbol(value: &Value, native_symbol: &str, raw: bool) { + if raw { + println!("{}", pretty(value)); + return; + } + + if let Some(table) = try_format_detailed_peers(value) { + println!("{}", table); + return; + } + if let Some(status) = try_format_node_status(value) { + println!("{}", status); + return; + } + if let Some(table) = try_format_peer_scores(value) { + println!("{}", table); + return; + } + if let Some(table) = try_format_banned_subnets(value) { + println!("{}", table); + return; + } + + println!("{}", pretty(value)); + + let annotations = collect_annotations_with_symbol(value, native_symbol); + if !annotations.is_empty() { + println!("-- interpreted values --"); + for note in annotations { + println!("{note}"); + } + } +} + +fn pretty(value: &Value) -> String { + serde_json::to_string_pretty(value).unwrap_or_else(|_| value.to_string()) +} + +fn collect_annotations_with_symbol(value: &Value, native_symbol: &str) -> Vec { + let mut out = Vec::new(); + walk("$", value, native_symbol, &mut out); + out +} + +fn walk(path: &str, value: &Value, native_symbol: &str, out: &mut Vec) { + match value { + Value::Object(map) => { + for (k, v) in map { + walk(&format!("{path}.{k}"), v, native_symbol, out); + } + } + Value::Array(items) => { + for (idx, v) in items.iter().enumerate() { + walk(&format!("{path}[{idx}]"), v, native_symbol, out); + } + } + Value::String(s) => { + if let Some(dec) = small_hex_to_dec(s) { + out.push(format!("{path}: {s} -> {dec}")); + if looks_like_wei(dec) { + out.push(format!("{path}: {dec} wei -> {} {native_symbol}", format_eth(dec))); + } + } + if let Some(wei) = decimal_like_wei(s) { + out.push(format!("{path}: {wei} wei -> {} {native_symbol}", format_eth(wei))); + } + } + Value::Number(n) => { + if let Some(wei) = n.as_u64().map(u128::from) + && looks_like_wei(wei) + { + out.push(format!("{path}: {wei} wei -> {} {native_symbol}", format_eth(wei))); + } + } + _ => {} + } +} + +fn small_hex_to_dec(input: &str) -> Option { + if !(input.starts_with("0x") || input.starts_with("0X")) { + return None; + } + let hex = &input[2..]; + if hex.is_empty() || hex.len() > 32 { + return None; + } + u128::from_str_radix(hex, 16).ok() +} + +fn decimal_like_wei(input: &str) -> Option { + if input.is_empty() || !input.chars().all(|c| c.is_ascii_digit()) { + return None; + } + let value = input.parse::().ok()?; + if looks_like_wei(value) { Some(value) } else { None } +} + +fn looks_like_wei(value: u128) -> bool { + (WEI_HEURISTIC_MIN..=WEI_HEURISTIC_MAX).contains(&value) +} + +fn format_eth(wei: u128) -> String { + const WEI_PER_ETH: u128 = 1_000_000_000_000_000_000; + let whole = wei / WEI_PER_ETH; + let frac = wei % WEI_PER_ETH; + if frac == 0 { + return whole.to_string(); + } + let mut frac_str = format!("{frac:018}"); + while frac_str.ends_with('0') { + frac_str.pop(); + } + format!("{whole}.{frac_str}") +} + +fn try_format_detailed_peers(value: &Value) -> Option { + let peers = value.as_array()?; + if peers.is_empty() { + return Some("-- no peers connected --".to_string()); + } + + let first = peers.first()?; + if !first.is_object() { + return None; + } + + let obj = first.as_object()?; + if !obj.contains_key("peerId") && !obj.contains_key("peer_id") { + return None; + } + + let mut lines = vec![]; + let header = format!( + "{:<18} {:<18} {:<4} {:<4} {:<6} {:<14} {:<8} {:<10}", + "PEER", "ADDR", "DIR", "REP", "BLOCK", "CLIENT", "STATE", "PoG" + ); + lines.push(header); + + for peer in peers { + if let Some(peer_obj) = peer.as_object() { + let peer_id = peer_obj + .get("peerId") + .or_else(|| peer_obj.get("peer_id")) + .and_then(|v| v.as_str()) + .unwrap_or("?"); + let addr = peer_obj + .get("remoteAddr") + .or_else(|| peer_obj.get("remote_addr")) + .and_then(|v| v.as_str()) + .unwrap_or("?"); + let direction = peer_obj + .get("direction") + .and_then(|v| v.as_str()) + .map(|s| chars_prefix(s, 3)) + .unwrap_or("-"); + let reputation = peer_obj + .get("reputation") + .and_then(|v| v.as_i64()) + .map(|r| r.to_string()) + .unwrap_or_else(|| "?".to_string()); + let block = peer_obj + .get("latestBlock") + .or_else(|| peer_obj.get("latest_block")) + .and_then(|v| v.as_u64()) + .map(|b| b.to_string()) + .unwrap_or_else(|| "?".to_string()); + let client = peer_obj + .get("clientVersion") + .or_else(|| peer_obj.get("client_version")) + .and_then(|v| v.as_str()) + .unwrap_or("-"); + let client_short = if client.chars().count() > 14 { + ellipsis_char_ends(client, 8, 3) + } else { + client.to_string() + }; + let state = peer_obj + .get("connectionState") + .or_else(|| peer_obj.get("connection_state")) + .and_then(|v| v.as_str()) + .unwrap_or("-"); + + let pog_str = if let Some(pog) = peer_obj.get("pog") { + if pog.is_null() { + "-".to_string() + } else if let Some(pog_obj) = pog.as_object() { + let failures = pog_obj + .get("failureCount") + .or_else(|| pog_obj.get("failure_count")) + .and_then(|v| v.as_u64()) + .unwrap_or(0); + format!("{}", failures) + } else { + "-".to_string() + } + } else { + "-".to_string() + }; + + let peer_short = if peer_id.chars().count() > 12 { + ellipsis_char_ends(peer_id, 6, 4) + } else { + peer_id.to_string() + }; + + let line = format!( + "{:<18} {:<18} {:<4} {:<4} {:<6} {:<14} {:<8} {:<10}", + peer_short, addr, direction, reputation, block, client_short, state, pog_str + ); + lines.push(line); + } + } + + Some(lines.join("\n")) +} + +fn try_format_node_status(value: &Value) -> Option { + let obj = value.as_object()?; + + if !obj.contains_key("chainId") + && !obj.contains_key("chain_id") + && !obj.contains_key("genesisHash") + && !obj.contains_key("genesis_hash") + && !obj.contains_key("headNumber") + && !obj.contains_key("head_number") + { + return None; + } + + let chain = obj + .get("chainId") + .or_else(|| obj.get("chain_id")) + .or_else(|| obj.get("networkId")) + .or_else(|| obj.get("network_id")) + .and_then(hex_or_decimal_to_u64) + .unwrap_or(0); + let genesis = obj + .get("genesisHash") + .or_else(|| obj.get("genesis_hash")) + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let genesis_short = if genesis.chars().count() > 12 { + ellipsis_char_ends(genesis, 6, 4) + } else { + genesis.to_string() + }; + let head = obj + .get("headNumber") + .or_else(|| obj.get("head_number")) + .and_then(hex_or_decimal_to_u64) + .unwrap_or(0); + let head_hash = obj + .get("headHash") + .or_else(|| obj.get("head_hash")) + .or_else(|| obj.get("head")) + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let head_hash_short = if head_hash.chars().count() > 12 { + ellipsis_char_ends(head_hash, 6, 4) + } else { + head_hash.to_string() + }; + let syncing = obj.get("syncing").and_then(|v| v.as_bool()).unwrap_or(false); + let peers_total = obj + .get("peerCountTotal") + .or_else(|| obj.get("peer_count_total")) + .and_then(hex_or_decimal_to_u64) + .unwrap_or(0); + let peers_in = obj + .get("peerCountInbound") + .or_else(|| obj.get("peer_count_inbound")) + .and_then(hex_or_decimal_to_u64) + .unwrap_or(0); + let peers_out = obj + .get("peerCountOutbound") + .or_else(|| obj.get("peer_count_outbound")) + .and_then(hex_or_decimal_to_u64) + .unwrap_or(0); + let client = obj + .get("clientVersion") + .or_else(|| obj.get("client_version")) + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + + let output = format!( + "chain={} genesis={} fork=unknown\nhead={} ({}) syncing={}\npeers={} (in={} out={}) client={} net={}", + chain, + genesis_short, + head, + head_hash_short, + syncing, + peers_total, + peers_in, + peers_out, + client, + chain + ); + + Some(output) +} + +fn try_format_peer_scores(value: &Value) -> Option { + let scores = value.as_array()?; + if scores.is_empty() { + return Some("-- no peers scored --".to_string()); + } + + let first = scores.first()?; + if !first.is_object() { + return None; + } + + let obj = first.as_object()?; + // Detect if this looks like peer scores: should have fields like peerId, threatScore, node, + // policies + if !obj.contains_key("peerId") && !obj.contains_key("peer_id") { + return None; + } + if !obj.contains_key("threatScore") && !obj.contains_key("threat_score") { + return None; + } + + let mut lines = vec![]; + let header = + format!("{:<18} {:<6} {:<10} {:<14} {:<8}", "PEER", "THREAT", "NODE", "REASON", "POLICIES"); + lines.push(header); + + for score in scores { + if let Some(score_obj) = score.as_object() { + let peer_id = score_obj + .get("peerId") + .or_else(|| score_obj.get("peer_id")) + .and_then(|v| v.as_str()) + .unwrap_or("?"); + let threat = score_obj + .get("threatScore") + .or_else(|| score_obj.get("threat_score")) + .and_then(|v| v.as_u64()) + .map(|t| t.to_string()) + .unwrap_or_else(|| "?".to_string()); + let node = score_obj.get("node").and_then(|v| v.as_str()).unwrap_or("?"); + let reason = score_obj.get("reason").and_then(|v| v.as_str()).unwrap_or("-"); + + let policies = score_obj + .get("policies") + .and_then(|v| v.as_array()) + .map(|p| p.len().to_string()) + .unwrap_or_else(|| "0".to_string()); + + let peer_short = if peer_id.chars().count() > 12 { + ellipsis_char_ends(peer_id, 6, 4) + } else { + peer_id.to_string() + }; + let reason_short = if reason.chars().count() > 14 { + ellipsis_char_ends(reason, 8, 3) + } else { + reason.to_string() + }; + + let line = format!( + "{:<18} {:<6} {:<10} {:<14} {:<8}", + peer_short, threat, node, reason_short, policies + ); + lines.push(line); + } + } + + Some(lines.join("\n")) +} + +fn try_format_banned_subnets(value: &Value) -> Option { + let subnets = value.as_array()?; + if subnets.is_empty() { + return Some("-- no subnets banned --".to_string()); + } + + let first = subnets.first()?; + if !first.is_object() { + return None; + } + + let obj = first.as_object()?; + // Detect if this looks like banned subnets: should have fields like subnet, reason, peers, + // nodes + if !obj.contains_key("subnet") && !obj.contains_key("cidr") { + return None; + } + + let mut lines = vec![]; + let header = format!("{:<20} {:<14} {:<8} {:<20}", "SUBNET", "REASON", "PEERS", "NODES"); + lines.push(header); + + for subnet in subnets { + if let Some(subnet_obj) = subnet.as_object() { + let cidr = subnet_obj + .get("subnet") + .or_else(|| subnet_obj.get("cidr")) + .and_then(|v| v.as_str()) + .unwrap_or("?"); + let reason = subnet_obj.get("reason").and_then(|v| v.as_str()).unwrap_or("-"); + let peer_count = subnet_obj + .get("peerCount") + .or_else(|| subnet_obj.get("peer_count")) + .and_then(|v| v.as_u64()) + .map(|p| p.to_string()) + .unwrap_or_else(|| "?".to_string()); + let nodes = subnet_obj + .get("nodes") + .and_then(|v| v.as_array()) + .map(|n| n.len().to_string()) + .unwrap_or_else(|| "?".to_string()); + + let reason_short = if reason.chars().count() > 14 { + ellipsis_char_ends(reason, 8, 3) + } else { + reason.to_string() + }; + + let line = format!("{:<20} {:<14} {:<8} {:<20}", cidr, reason_short, peer_count, nodes); + lines.push(line); + } + } + + Some(lines.join("\n")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_small_hex() { + assert_eq!(small_hex_to_dec("0x2a"), Some(42)); + assert_eq!(small_hex_to_dec("0xffffffffffffffff"), Some(u64::MAX as u128)); + assert_eq!(small_hex_to_dec("0x10000000000000000"), Some(18446744073709551616)); + assert_eq!(small_hex_to_dec("0x100000000000000000000000000000000"), None); + } + + #[test] + fn formats_eth() { + assert_eq!(format_eth(1_000_000_000_000_000_000), "1"); + assert_eq!(format_eth(1_500_000_000_000_000_000), "1.5"); + } + + #[test] + fn annotates_wei_and_hex() { + let value = serde_json::json!({ + "gasUsed": "0x5208", + "amount": "1000000000000000000" + }); + let notes = collect_annotations_with_symbol(&value, DEFAULT_NATIVE_SYMBOL); + assert!(notes.iter().any(|n| n.contains("0x5208 -> 21000"))); + assert!(notes.iter().any(|n| n.contains("1 ETH"))); + } + + #[test] + fn annotates_hex_wei_as_eth() { + let value = serde_json::json!("0x0de0b6b3a7640000"); + let notes = collect_annotations_with_symbol(&value, DEFAULT_NATIVE_SYMBOL); + assert!(notes.iter().any(|n| n.contains("1000000000000000000"))); + assert!(notes.iter().any(|n| n.contains("1 ETH"))); + } + + #[test] + fn detects_bera_native_symbol() { + assert_eq!(native_symbol_for_chain_id(Some(80_069)), "BERA"); + assert_eq!(native_symbol_for_chain_id(Some(80_094)), "BERA"); + assert_eq!(native_symbol_for_chain_id(Some(1)), "ETH"); + assert_eq!(native_symbol_for_chain_id(None), "ETH"); + } + + #[test] + fn annotates_native_symbol_for_chain() { + let value = serde_json::json!("1000000000000000000"); + let notes = collect_annotations_with_symbol(&value, "BERA"); + assert!(notes.iter().any(|n| n.contains("1 BERA"))); + } + + #[test] + fn formats_peer_scores_table() { + let scores = serde_json::json!([ + { + "peerId": "0xabcdef1234567890abcdef1234567890abcdef12", + "threatScore": 150, + "node": "node-1", + "reason": "stale_head", + "policies": ["stale_head", "subnet_concentration"] + } + ]); + let formatted = try_format_peer_scores(&scores); + assert!(formatted.is_some()); + let formatted_str = formatted.unwrap(); + assert!(formatted_str.contains("PEER")); + assert!(formatted_str.contains("THREAT")); + assert!(formatted_str.contains("0xabcd..ef12")); + assert!(formatted_str.contains("150")); + } + + #[test] + fn formats_banned_subnets_table() { + let subnets = serde_json::json!([ + { + "subnet": "192.168.1.0/24", + "reason": "subnet_concentration", + "peerCount": 5, + "nodes": ["node-1", "node-2"] + } + ]); + let formatted = try_format_banned_subnets(&subnets); + assert!(formatted.is_some()); + let formatted_str = formatted.unwrap(); + assert!(formatted_str.contains("SUBNET")); + assert!(formatted_str.contains("PEERS")); + assert!(formatted_str.contains("192.168.1.0/24")); + assert!(formatted_str.contains("5")); + } + + #[test] + fn handles_empty_peer_scores_gracefully() { + let empty_scores = serde_json::json!([]); + let formatted = try_format_peer_scores(&empty_scores); + assert_eq!(formatted, Some("-- no peers scored --".to_string())); + } + + #[test] + fn handles_empty_banned_subnets_gracefully() { + let empty_subnets = serde_json::json!([]); + let formatted = try_format_banned_subnets(&empty_subnets); + assert_eq!(formatted, Some("-- no subnets banned --".to_string())); + } + + #[test] + fn chars_prefix_never_splits_codepoints() { + assert_eq!(chars_prefix("μμμbound", 3), "μμμ"); + assert_eq!(chars_prefix("μμμbound", 0), ""); + } + + #[test] + fn ellipsis_char_ends_counts_chars_not_bytes() { + let out = ellipsis_char_ends("abcdefghijklmnopqrs", 6, 4); + assert_eq!(out, "abcdef..pqrs"); + } +} diff --git a/src/console/query.rs b/src/console/query.rs new file mode 100644 index 00000000..471cccb3 --- /dev/null +++ b/src/console/query.rs @@ -0,0 +1,203 @@ +use eyre::{Result, bail, eyre}; +use serde_json::{Number, Value}; + +#[derive(Debug, Clone)] +enum Segment { + Field(String), + Index(usize), +} + +pub fn apply_query(expr: &str, input: &Value) -> Result { + let expr = expr.trim(); + if !expr.starts_with('.') { + bail!("query must start with '.'"); + } + + if let Some((inner, rest)) = parse_map(expr)? { + let items = input + .as_array() + .ok_or_else(|| eyre!(".map(...) requires last result to be an array"))?; + let mut out = Vec::with_capacity(items.len()); + for item in items { + out.push(apply_query(inner, item)?); + } + let mapped = Value::Array(out); + if rest.is_empty() { + return Ok(mapped); + } + return apply_query(rest, &mapped); + } + + if expr == ".count" || expr == ".len" { + return count_value(input); + } + if expr == ".first" { + return first_value(input); + } + if expr == ".last" { + return last_value(input); + } + + let segments = parse_segments(expr)?; + let mut current = input; + for segment in segments { + current = match segment { + Segment::Field(name) => { + current.get(&name).ok_or_else(|| eyre!("field {name:?} not found"))? + } + Segment::Index(i) => current.get(i).ok_or_else(|| eyre!("index {i} out of range"))?, + }; + } + Ok(current.clone()) +} + +fn parse_map(expr: &str) -> Result> { + if !expr.starts_with(".map(") { + return Ok(None); + } + let mut depth = 1usize; + let mut close = None; + for (i, b) in expr.bytes().enumerate().skip(5) { + match b { + b'(' => depth += 1, + b')' => { + depth -= 1; + if depth == 0 { + close = Some(i); + break; + } + } + _ => {} + } + } + let close = close.ok_or_else(|| eyre!("invalid .map(...) expression"))?; + let inner = &expr[5..close]; + if !inner.starts_with('.') { + bail!("map selector must start with '.'"); + } + let rest = &expr[close + 1..]; + Ok(Some((inner, rest))) +} + +fn parse_segments(expr: &str) -> Result> { + let mut out = Vec::new(); + let bytes = expr.as_bytes(); + let mut i = 0usize; + while i < bytes.len() { + if bytes[i] != b'.' { + bail!("invalid query syntax near {}", &expr[i..]); + } + i += 1; + if i >= bytes.len() { + break; + } + if bytes[i] == b'[' { + i += 1; + let start = i; + while i < bytes.len() && bytes[i] != b']' { + i += 1; + } + if i >= bytes.len() { + bail!("unterminated index in query"); + } + let idx: usize = expr[start..i].parse()?; + out.push(Segment::Index(idx)); + i += 1; + continue; + } + let start = i; + while i < bytes.len() { + let c = bytes[i]; + if c == b'.' || c == b'[' { + break; + } + i += 1; + } + let name = expr[start..i].trim(); + if name.is_empty() { + bail!("empty field in query"); + } + out.push(Segment::Field(name.to_owned())); + } + Ok(out) +} + +fn count_value(value: &Value) -> Result { + match value { + Value::Array(items) => Ok(Value::Number(Number::from(items.len() as u64))), + Value::Object(fields) => Ok(Value::Number(Number::from(fields.len() as u64))), + _ => Err(eyre!(".count/.len only apply to arrays and objects")), + } +} + +fn first_value(value: &Value) -> Result { + let items = value.as_array().ok_or_else(|| eyre!(".first only applies to arrays"))?; + Ok(items.first().cloned().unwrap_or(Value::Null)) +} + +fn last_value(value: &Value) -> Result { + let items = value.as_array().ok_or_else(|| eyre!(".last only applies to arrays"))?; + Ok(items.last().cloned().unwrap_or(Value::Null)) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn applies_count() { + let value = json!([1, 2, 3]); + let out = apply_query(".count", &value).unwrap(); + assert_eq!(out, json!(3)); + } + + #[test] + fn applies_len() { + let value = json!({"a": 1, "b": 2}); + let out = apply_query(".len", &value).unwrap(); + assert_eq!(out, json!(2)); + } + + #[test] + fn applies_index_and_field() { + let value = json!([{ "a": 1 }, { "a": 2 }]); + let out = apply_query(".[1].a", &value).unwrap(); + assert_eq!(out, json!(2)); + } + + #[test] + fn applies_map() { + let value = json!([{ "a": 1 }, { "a": 2 }]); + let out = apply_query(".map(.a)", &value).unwrap(); + assert_eq!(out, json!([1, 2])); + } + + #[test] + fn applies_map_then_count() { + let value = json!([{ "a": 1 }, { "a": 2 }, { "a": 3 }]); + let out = apply_query(".map(.a).count", &value).unwrap(); + assert_eq!(out, json!(3)); + } + + #[test] + fn first_and_last_on_empty_array_return_null() { + let value = json!([]); + assert_eq!(apply_query(".first", &value).unwrap(), Value::Null); + assert_eq!(apply_query(".last", &value).unwrap(), Value::Null); + } + + #[test] + fn map_requires_array_input() { + let value = json!({"a": 1}); + let err = apply_query(".map(.a)", &value).unwrap_err(); + assert!(err.to_string().contains("requires last result to be an array")); + } + + #[test] + fn count_rejects_scalars() { + let value = json!("abc"); + let err = apply_query(".count", &value).unwrap_err(); + assert!(err.to_string().contains("only apply to arrays and objects")); + } +} diff --git a/src/console/repl.rs b/src/console/repl.rs new file mode 100644 index 00000000..058fabb4 --- /dev/null +++ b/src/console/repl.rs @@ -0,0 +1,322 @@ +use super::{ + endpoint::{ResolvedEndpoint, default_datadir}, + engine::{EvalOutcome, evaluate_line}, + output::{BERACHAIN_CHAIN_IDS, hex_or_decimal_to_u64, print_value_for_chain_raw}, + rpc::RpcClient, +}; +use eyre::Result; +use reedline::{ + ColumnarMenu, Completer, Emacs, FileBackedHistory, HISTORY_SIZE, KeyCode, KeyModifiers, + MenuBuilder, Prompt, PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus, Reedline, + ReedlineEvent, ReedlineMenu, Signal, Span, Suggestion, default_emacs_keybindings, +}; +use serde_json::Value; +use std::{borrow::Cow, collections::BTreeMap, path::PathBuf}; + +const COMPLETION_MENU_NAME: &str = "completion_menu"; + +fn completion_keybindings() -> reedline::Keybindings { + let mut kb = default_emacs_keybindings(); + kb.add_binding( + KeyModifiers::NONE, + KeyCode::Tab, + ReedlineEvent::UntilFound(vec![ + ReedlineEvent::Menu(COMPLETION_MENU_NAME.to_string()), + ReedlineEvent::MenuNext, + ]), + ); + kb +} + +/// Single-line prompt matching the previous `rustyline` `readline("bera> ")` UX. +struct BeraPrompt; + +impl Prompt for BeraPrompt { + fn render_prompt_left(&self) -> Cow<'_, str> { + Cow::Borrowed("bera> ") + } + + fn render_prompt_right(&self) -> Cow<'_, str> { + Cow::Borrowed("") + } + + fn render_prompt_indicator(&self, _prompt_mode: PromptEditMode) -> Cow<'_, str> { + Cow::Borrowed("") + } + + fn render_prompt_multiline_indicator(&self) -> Cow<'_, str> { + Cow::Borrowed(".. ") + } + + fn render_prompt_history_search_indicator( + &self, + history_search: PromptHistorySearch, + ) -> Cow<'_, str> { + let prefix = match history_search.status { + PromptHistorySearchStatus::Passing => "", + PromptHistorySearchStatus::Failing => "failing ", + }; + Cow::Owned(format!("({}reverse-search: {}) ", prefix, history_search.term)) + } +} + +#[allow(clippy::too_many_arguments)] +pub async fn run_repl( + rpc: &RpcClient, + history_path: PathBuf, + endpoint: ResolvedEndpoint, + chain_id: Option, + raw: bool, + has_bera_admin: bool, + bera_admin_status: Option, +) -> Result<()> { + std::fs::create_dir_all( + history_path.parent().map(ToOwned::to_owned).unwrap_or_else(|| PathBuf::from(".")), + )?; + + let modules = rpc.supported_modules().await.unwrap_or_default(); + let helper = CompletionHelper::new(&modules, has_bera_admin); + + let history = FileBackedHistory::with_file(HISTORY_SIZE, history_path.clone()) + .map_err(|e| eyre::eyre!("failed to load console history: {e}"))?; + + let completion_menu = Box::new(ColumnarMenu::default().with_name(COMPLETION_MENU_NAME)); + let edit_mode = Box::new(Emacs::new(completion_keybindings())); + + let mut editor = Reedline::create() + .with_history(Box::new(history)) + .with_completer(Box::new(helper)) + .with_menu(ReedlineMenu::EngineCompleter(completion_menu)) + .with_edit_mode(edit_mode) + .with_quick_completions(true); + + let prompt = BeraPrompt; + + println!("bera-reth console :: {}", endpoint.raw); + print_startup_snapshot(rpc, chain_id, bera_admin_status.as_ref()).await; + println!("help: commands | ctrl-d / exit: quit"); + + let mut last_rpc_result = None; + loop { + match editor.read_line(&prompt) { + Ok(Signal::Success(line)) => { + match evaluate_line(rpc, &line, &mut last_rpc_result).await { + Ok(EvalOutcome::Noop) => {} + Ok(EvalOutcome::Exit) => break, + Ok(EvalOutcome::Help) => print_help(), + Ok(EvalOutcome::Value(value)) => { + print_value_for_chain_raw(&value, chain_id, raw); + } + Err(err) => eprintln!("error: {err}"), + } + } + Ok(Signal::CtrlC) => {} + Ok(Signal::CtrlD) => break, + Ok(_) => {} + Err(err) => return Err(err.into()), + } + } + + Ok(()) +} + +async fn print_startup_snapshot( + rpc: &RpcClient, + chain_id: Option, + bera_admin_status: Option<&Value>, +) { + if let Some(status) = bera_admin_status { + let client_version = status + .get("clientVersion") + .or_else(|| status.get("client_version")) + .and_then(as_string); + let network_id = + status.get("networkId").or_else(|| status.get("network_id")).and_then(as_string); + let head_number = status + .get("headNumber") + .or_else(|| status.get("head_number")) + .and_then(|v| hex_or_decimal_to_u64(v).map(|n| n.to_string())) + .or_else(|| status.get("head").and_then(as_string)); + let peer_count_total = status + .get("peerCountTotal") + .or_else(|| status.get("peer_count_total")) + .and_then(hex_or_decimal_to_u64); + let peer_count_inbound = status + .get("peerCountInbound") + .or_else(|| status.get("peer_count_inbound")) + .and_then(hex_or_decimal_to_u64); + let peer_count_outbound = status + .get("peerCountOutbound") + .or_else(|| status.get("peer_count_outbound")) + .and_then(hex_or_decimal_to_u64); + + let peers_str = if let (Some(in_count), Some(out_count)) = + (peer_count_inbound, peer_count_outbound) + { + format!("peers={} (in={} out={})", peer_count_total.unwrap_or(0), in_count, out_count) + } else { + format!("peers={}", peer_count_total.unwrap_or(0)) + }; + + println!( + "node :: {} | net={}{} | block={} | {}", + client_version.unwrap_or_else(|| "unavailable".to_owned()), + network_id.unwrap_or_else(|| "unavailable".to_owned()), + chain_emoji(chain_id), + head_number.unwrap_or_else(|| "unavailable".to_owned()), + peers_str + ); + } else { + let version = + rpc.request_value("web3_clientVersion", None).await.ok().and_then(|v| as_string(&v)); + let block = rpc + .request_value("eth_blockNumber", None) + .await + .ok() + .and_then(|v| hex_or_decimal_to_u64(&v).map(|n| n.to_string())); + let peers = rpc + .request_value("net_peerCount", None) + .await + .ok() + .and_then(|v| hex_or_decimal_to_u64(&v).map(|n| n.to_string())); + let network = rpc.request_value("net_version", None).await.ok().and_then(|v| as_string(&v)); + + println!( + "node :: version={} | net={}{} | block={} | peers={}", + version.unwrap_or_else(|| "unavailable".to_owned()), + network.unwrap_or_else(|| "unavailable".to_owned()), + chain_emoji(chain_id), + block.unwrap_or_else(|| "unavailable".to_owned()), + peers.unwrap_or_else(|| "unavailable".to_owned()), + ); + } +} + +fn chain_emoji(chain_id: Option) -> &'static str { + match chain_id { + Some(id) if BERACHAIN_CHAIN_IDS.contains(&id) => " 🐻", + _ => "", + } +} + +fn as_string(value: &Value) -> Option { + match value { + Value::String(s) => Some(s.clone()), + Value::Number(n) => Some(n.to_string()), + _ => None, + } +} + +fn print_help() { + println!("Commands:"); + println!( + " [json_params] (RPC call; dots become underscores, e.g. eth.blockNumber)" + ); + println!(" TAB completion for RPC namespaces/methods"); + println!(" help | exit"); + println!("Queries (run against last RPC result):"); + println!(" .count | .len | .first | .last | .[0] | .[0].field | .map(.field)"); + println!("Destructive (calls admin.removePeer for each connected peer):"); + println!(" removeAllPeers | admin.removeAllPeers"); +} + +struct CompletionHelper { + words: Vec, +} + +impl CompletionHelper { + fn new(modules: &BTreeMap, has_bera_admin: bool) -> CompletionHelper { + let mut words = vec![ + "help".to_owned(), + "exit".to_owned(), + "quit".to_owned(), + ".count".to_owned(), + ".len".to_owned(), + ".first".to_owned(), + ".last".to_owned(), + ".map(".to_owned(), + ]; + for module in modules.keys() { + words.push(format!("{module}.")); + words.push(format!("{module}_")); + words.extend(super::rpc_completion::dot_completions_for_namespace(module)); + } + if has_bera_admin { + words.push("beradmin.".to_owned()); + words.push("beradmin_".to_owned()); + words.extend(super::rpc_completion::dot_completions_for_namespace("beradmin")); + } + words.sort(); + words.dedup(); + CompletionHelper { words } + } +} + +impl Completer for CompletionHelper { + fn complete(&mut self, line: &str, pos: usize) -> Vec { + let safe_pos = pos.min(line.len()); + let up_to_cursor = &line[..safe_pos]; + let start = up_to_cursor + .char_indices() + .rev() + .find(|(_, c)| c.is_whitespace()) + .map(|(i, c)| i + c.len_utf8()) + .unwrap_or(0); + let needle = &up_to_cursor[start..]; + self.words + .iter() + .filter(|word| word.starts_with(needle)) + .map(|word| Suggestion { + value: word.clone(), + span: Span::new(start, safe_pos), + append_whitespace: false, + ..Default::default() + }) + .collect() + } +} + +pub fn history_file_path() -> PathBuf { + default_datadir().join("bera-reth-console-history") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn completion_includes_bera_admin_when_enabled() { + let modules = BTreeMap::new(); + let helper = CompletionHelper::new(&modules, true); + assert!(helper.words.iter().any(|w| w == "beradmin.detailedPeers")); + } + + #[test] + fn completion_excludes_bera_admin_when_disabled() { + let modules = BTreeMap::new(); + let helper = CompletionHelper::new(&modules, false); + assert!(!helper.words.iter().any(|w| w == "beradmin.detailedPeers")); + } + + #[test] + fn completion_matches_prefix() { + let modules = BTreeMap::from([("eth".to_owned(), "1.0".to_owned())]); + let mut helper = CompletionHelper::new(&modules, false); + let hits = helper.complete("eth.getB", "eth.getB".len()); + assert!(hits.iter().any(|s| s.value == "eth.getBalance")); + } + + #[test] + fn completion_includes_eth_namespace_methods() { + let modules = BTreeMap::from([("eth".to_owned(), "1.0".to_owned())]); + let helper = CompletionHelper::new(&modules, false); + assert!(helper.words.iter().any(|w| w == "eth.getLogs")); + assert!(helper.words.iter().any(|w| w == "eth.getTransactionReceipt")); + } + + #[test] + fn parses_hex_or_decimal_numbers() { + use serde_json::json; + assert_eq!(hex_or_decimal_to_u64(&json!("0x10")), Some(16)); + } +} diff --git a/src/console/rpc.rs b/src/console/rpc.rs new file mode 100644 index 00000000..33263596 --- /dev/null +++ b/src/console/rpc.rs @@ -0,0 +1,238 @@ +use super::endpoint::{ResolvedEndpoint, Transport}; +use eyre::{Result, eyre}; +use serde_json::{Map, Value}; +use std::{ + collections::BTreeMap, + ffi::CString, + path::Path, + sync::atomic::{AtomicU64, Ordering}, +}; +use tokio::{ + io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, + net::UnixStream, +}; + +#[derive(Debug)] +pub enum RpcClient { + Ipc(IpcClientLite), +} + +impl RpcClient { + pub async fn connect(endpoint: &ResolvedEndpoint) -> Result { + match endpoint.transport { + Transport::Ipc => { + validate_ipc_endpoint(&endpoint.raw)?; + let client = IpcClientLite::new(endpoint.raw.clone()); + Ok(Self::Ipc(client)) + } + } + } + + pub async fn request_value(&self, method: &str, params: Option) -> Result { + let params = RpcParams::from_value(params)?; + match self { + Self::Ipc(client) => client.request(method, params.into_value()).await, + } + } + + pub async fn supported_modules(&self) -> Result> { + let value = self.request_value("rpc_modules", None).await?; + serde_json::from_value(value) + .map_err(|e| eyre!("failed to parse rpc_modules response as a JSON object: {e}")) + } +} + +enum RpcParams { + None, + Array(Vec), + Object(Map), +} + +impl RpcParams { + fn from_value(value: Option) -> Result { + let Some(value) = value else { + return Ok(Self::None); + }; + match value { + Value::Null => Ok(Self::None), + Value::Array(values) => Ok(Self::Array(values)), + Value::Object(values) => Ok(Self::Object(values)), + _ => Err(eyre!("rpc params must be null, JSON array, or JSON object")), + } + } + + fn into_value(self) -> Value { + match self { + Self::None => Value::Array(vec![]), + Self::Array(values) => Value::Array(values), + Self::Object(values) => Value::Object(values), + } + } +} + +fn validate_ipc_endpoint(path: &str) -> Result<()> { + let endpoint = Path::new(path); + if !endpoint.exists() { + return Err(eyre!("IPC endpoint not found: {path}")); + } + let metadata = std::fs::metadata(endpoint) + .map_err(|err| eyre!("failed to stat IPC endpoint {path}: {err}"))?; + #[cfg(unix)] + { + use std::os::unix::fs::FileTypeExt; + if !metadata.file_type().is_socket() { + return Err(eyre!("IPC endpoint is not a unix socket: {path}")); + } + let c_path = + CString::new(path).map_err(|_| eyre!("IPC endpoint contains invalid bytes: {path}"))?; + let read_ok = unsafe { libc::access(c_path.as_ptr(), libc::R_OK) == 0 }; + if !read_ok { + return Err(eyre!("IPC endpoint is not readable by current user: {path}")); + } + let write_ok = unsafe { libc::access(c_path.as_ptr(), libc::W_OK) == 0 }; + if !write_ok { + return Err(eyre!("IPC endpoint is not writable by current user: {path}")); + } + } + #[cfg(not(unix))] + { + let _ = metadata; + } + Ok(()) +} + +#[derive(Debug)] +pub(crate) struct IpcClientLite { + path: String, + next_id: AtomicU64, +} + +impl IpcClientLite { + fn new(path: String) -> Self { + Self { path, next_id: AtomicU64::new(1) } + } + + async fn request(&self, method: &str, params: Value) -> Result { + const IPC_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); + tokio::time::timeout(IPC_TIMEOUT, self.request_inner(method, params)) + .await + .map_err(|_| eyre!("IPC request timed out after {IPC_TIMEOUT:?}"))? + } + + async fn request_inner(&self, method: &str, params: Value) -> Result { + let id = self.next_id.fetch_add(1, Ordering::Relaxed); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": id, + "method": method, + "params": params, + }); + let mut stream = UnixStream::connect(&self.path) + .await + .map_err(|err| eyre!("failed to connect IPC endpoint {}: {err}", self.path))?; + let encoded = serde_json::to_string(&req)?; + stream.write_all(encoded.as_bytes()).await?; + stream.write_all(b"\n").await?; + + let mut reader = BufReader::new(stream); + let mut line = String::new(); + reader.read_line(&mut line).await?; + if line.trim().is_empty() { + return Err(eyre!("empty IPC response")); + } + + let resp: Value = serde_json::from_str(&line)?; + if let Some(err) = resp.get("error").filter(|e| !e.is_null()) { + return Err(eyre!("rpc error: {}", err)); + } + resp.get("result").cloned().ok_or_else(|| eyre!("missing result field in IPC response")) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use serde_json::json; + use tempfile::tempdir; + use tokio::{ + io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, + net::UnixListener, + }; + + #[test] + fn rpc_params_accept_none_and_null() { + let none_params = RpcParams::from_value(None).unwrap(); + assert!(matches!(none_params, RpcParams::None)); + + let null_params = RpcParams::from_value(Some(Value::Null)).unwrap(); + assert!(matches!(null_params, RpcParams::None)); + } + + #[test] + fn rpc_params_reject_scalar_values() { + let err = match RpcParams::from_value(Some(json!(true))) { + Ok(_) => panic!("expected scalar params to be rejected"), + Err(err) => err, + }; + assert!(err.to_string().contains("rpc params must be null, JSON array, or JSON object")); + } + + #[test] + fn rpc_params_preserve_array_and_object_shapes() { + let array = RpcParams::from_value(Some(json!([1, "x"]))).unwrap(); + assert_eq!(array.into_value(), json!([1, "x"])); + + let object = RpcParams::from_value(Some(json!({"a": 1, "b": "x"}))).unwrap(); + assert_eq!(object.into_value(), json!({"a": 1, "b": "x"})); + } + + #[test] + fn validate_ipc_endpoint_errors_for_missing_and_non_socket() { + let missing = validate_ipc_endpoint("/definitely/missing/reth.ipc").unwrap_err(); + assert!(missing.to_string().contains("IPC endpoint not found")); + + let dir = tempdir().expect("tempdir"); + let file_path = dir.path().join("plain-file"); + std::fs::write(&file_path, b"not a socket").expect("write file"); + let err = validate_ipc_endpoint(file_path.to_string_lossy().as_ref()).unwrap_err(); + assert!(err.to_string().contains("not a unix socket")); + } + + #[tokio::test(flavor = "multi_thread")] + async fn ipc_client_handles_empty_response_and_rpc_error() { + let dir = tempdir().expect("tempdir"); + let socket_path = dir.path().join("reth.ipc"); + let listener = UnixListener::bind(&socket_path).expect("bind socket"); + + let server_task = tokio::spawn(async move { + // First request: reply with an empty line. + let (stream1, _) = listener.accept().await.expect("accept first"); + let mut r1 = BufReader::new(stream1); + let mut req1 = String::new(); + let _ = r1.read_line(&mut req1).await.expect("read first"); + let mut s1 = r1.into_inner(); + s1.write_all(b"\n").await.expect("write empty response"); + + // Second request: reply with JSON-RPC error. + let (stream2, _) = listener.accept().await.expect("accept second"); + let mut r2 = BufReader::new(stream2); + let mut req2 = String::new(); + let _ = r2.read_line(&mut req2).await.expect("read second"); + let mut s2 = r2.into_inner(); + s2.write_all(br#"{"jsonrpc":"2.0","id":2,"error":{"code":-32000,"message":"boom"}}"#) + .await + .expect("write error"); + s2.write_all(b"\n").await.expect("write newline"); + }); + + let client = IpcClientLite::new(socket_path.to_string_lossy().to_string()); + let empty_err = client.request("eth_blockNumber", json!([])).await.unwrap_err(); + assert!(empty_err.to_string().contains("empty IPC response")); + + let rpc_err = client.request("eth_blockNumber", json!([])).await.unwrap_err(); + assert!(rpc_err.to_string().contains("rpc error")); + + server_task.await.expect("server task"); + } +} diff --git a/src/console/rpc_completion.rs b/src/console/rpc_completion.rs new file mode 100644 index 00000000..d674b2c5 --- /dev/null +++ b/src/console/rpc_completion.rs @@ -0,0 +1,349 @@ +//! Static method-name hints for the embedded `console` REPL. +//! +//! The REPL completes `namespace.method` tokens (e.g. `eth.getLogs`). JSON-RPC uses +//! `namespace_method`; this module only stores the **suffix** after the namespace +//! (the part after `_` or `.`), taken from upstream reth’s `#[method(name = "...")]` +//! macros in `rpc-eth-api` and `rpc-api`, plus Berachain’s `beradmin_*` surface. +//! When upstream adds RPCs, refresh these tables from the same reth sources. +//! +//! Use `RPC_NAMESPACE_TABLE` to walk all namespaces, or `method_suffixes` / +//! `dot_completions_for_namespace` for one namespace. + +/// Berachain extension namespace (`beradmin_*` JSON-RPC; matches `#[rpc(namespace = "beradmin")]`). +pub const BERA_ADMIN_METHOD_SUFFIXES: &[&str] = &[ + "detailedPeers", + "nodeStatus", + "banPeer", + "penalizePeer", + "prepareCanary", + "submitCanary", + "sealedBlockAttribution", +]; + +/// `eth_*` methods from reth. +pub const ETH_METHOD_SUFFIXES: &[&str] = &[ + "accounts", + "blobBaseFee", + "blockNumber", + "call", + "callBundle", + "callMany", + "cancelBundle", + "cancelPrivateTransaction", + "chainId", + "coinbase", + "config", + "createAccessList", + "estimateGas", + "feeHistory", + "fillTransaction", + "gasPrice", + "getAccount", + "getAccountInfo", + "getBalance", + "getBlockAccessListByBlockHash", + "getBlockAccessListByBlockNumber", + "getBlockByHash", + "getBlockByNumber", + "getBlockReceipts", + "getBlockTransactionCountByHash", + "getBlockTransactionCountByNumber", + "getCode", + "getFilterChanges", + "getFilterLogs", + "getHeaderByHash", + "getHeaderByNumber", + "getLogs", + "getProof", + "getRawTransactionByBlockHashAndIndex", + "getRawTransactionByBlockNumberAndIndex", + "getRawTransactionByHash", + "getStorageAt", + "getTransactionByBlockHashAndIndex", + "getTransactionByBlockNumberAndIndex", + "getTransactionByHash", + "getTransactionBySenderAndNonce", + "getTransactionCount", + "getTransactionReceipt", + "getUncleByBlockHashAndIndex", + "getUncleByBlockNumberAndIndex", + "getUncleCountByBlockHash", + "getUncleCountByBlockNumber", + "getWork", + "hashrate", + "maxPriorityFeePerGas", + "mining", + "newBlockFilter", + "newFilter", + "newPendingTransactionFilter", + "protocolVersion", + "sendBundle", + "sendPrivateRawTransaction", + "sendPrivateTransaction", + "sendRawTransaction", + "sendRawTransactionConditional", + "sendRawTransactionSync", + "sendTransaction", + "sign", + "signTransaction", + "signTypedData", + "simulateV1", + "submitHashrate", + "submitWork", + "syncing", + "uninstallFilter", +]; + +/// `net_*` methods from reth. +pub const NET_METHOD_SUFFIXES: &[&str] = &["listening", "peerCount", "version"]; + +/// `web3_*` methods from reth. +pub const WEB3_METHOD_SUFFIXES: &[&str] = &["clientVersion", "sha3"]; + +/// `txpool_*` methods from reth. +pub const TXPOOL_METHOD_SUFFIXES: &[&str] = &["content", "contentFrom", "inspect", "status"]; + +/// `rpc_*` methods from reth. +pub const RPC_API_METHOD_SUFFIXES: &[&str] = &["modules"]; + +/// `admin_*` methods from reth. +pub const ADMIN_METHOD_SUFFIXES: &[&str] = &[ + "addPeer", + "addTrustedPeer", + "clearTxpool", + "nodeInfo", + "peers", + "removePeer", + "removeTrustedPeer", +]; + +/// `trace_*` methods from reth. +pub const TRACE_METHOD_SUFFIXES: &[&str] = &[ + "block", + "blockOpcodeGas", + "call", + "callMany", + "filter", + "get", + "rawTransaction", + "replayBlockTransactions", + "replayTransaction", + "transaction", + "transactionOpcodeGas", +]; + +/// `debug_*` methods from reth. +pub const DEBUG_METHOD_SUFFIXES: &[&str] = &[ + "accountRange", + "backtraceAt", + "blockProfile", + "chainConfig", + "chaindbCompact", + "chaindbProperty", + "codeByHash", + "cpuProfile", + "dbAncient", + "dbAncients", + "dbGet", + "dumpBlock", + "executePayload", + "executionWitness", + "executionWitnessByBlockHash", + "freeOSMemory", + "freezeClient", + "gcStats", + "getAccessibleState", + "getBadBlocks", + "getBlockAccessList", + "getModifiedAccountsByHash", + "getModifiedAccountsByNumber", + "getRawBlock", + "getRawHeader", + "getRawReceipts", + "getRawTransaction", + "getRawTransactions", + "goTrace", + "intermediateRoots", + "memStats", + "mutexProfile", + "preimage", + "printBlock", + "seedHash", + "setBlockProfileRate", + "setGCPercent", + "setHead", + "setMutexProfileFraction", + "setTrieFlushInterval", + "stacks", + "standardTraceBadBlockToFile", + "standardTraceBlockToFile", + "startCPUProfile", + "startGoTrace", + "stateRootWithUpdates", + "stopCPUProfile", + "stopGoTrace", + "storageRangeAt", + "traceBadBlock", + "traceBlock", + "traceBlockByHash", + "traceBlockByNumber", + "traceCall", + "traceCallMany", + "traceChain", + "traceTransaction", + "verbosity", + "vmodule", + "writeBlockProfile", + "writeMemProfile", + "writeMutexProfile", +]; + +/// `engine_*` methods from reth. +pub const ENGINE_METHOD_SUFFIXES: &[&str] = &[ + "blockNumber", + "call", + "chainId", + "exchangeCapabilities", + "forkchoiceUpdatedV1", + "forkchoiceUpdatedV2", + "forkchoiceUpdatedV3", + "getBlobsV1", + "getBlobsV2", + "getBlobsV3", + "getBlockByHash", + "getBlockByNumber", + "getBlockReceipts", + "getClientVersionV1", + "getCode", + "getLogs", + "getPayloadBodiesByHashV1", + "getPayloadBodiesByHashV2", + "getPayloadBodiesByRangeV1", + "getPayloadBodiesByRangeV2", + "getPayloadV1", + "getPayloadV2", + "getPayloadV3", + "getPayloadV4", + "getPayloadV5", + "getPayloadV6", + "getProof", + "getTransactionReceipt", + "newPayloadV1", + "newPayloadV2", + "newPayloadV3", + "newPayloadV4", + "newPayloadV5", + "sendRawTransaction", + "syncing", +]; + +/// `reth_*` methods from reth. +pub const RETH_METHOD_SUFFIXES: &[&str] = &[ + "getBalanceChangesInBlock", + "subscribeChainNotifications", + "subscribeFinalizedChainNotifications", + "subscribePersistedBlock", +]; + +/// `ots_*` methods from reth. +pub const OTS_METHOD_SUFFIXES: &[&str] = &[ + "getApiLevel", + "getBlockDetails", + "getBlockDetailsByHash", + "getBlockTransactions", + "getContractCreator", + "getHeaderByNumber", + "getInternalOperations", + "getTransactionBySenderAndNonce", + "getTransactionError", + "hasCode", + "searchTransactionsAfter", + "searchTransactionsBefore", + "traceTransaction", +]; + +/// `miner_*` methods from reth. +pub const MINER_METHOD_SUFFIXES: &[&str] = &["setExtra", "setGasLimit", "setGasPrice"]; + +/// `mev_*` methods from reth. +pub const MEV_METHOD_SUFFIXES: &[&str] = &["sendBundle", "simBundle"]; + +/// `testing_*` methods from reth. +pub const TESTING_METHOD_SUFFIXES: &[&str] = &["buildBlockV1"]; + +/// `flashbots_*` methods from reth. +pub const FLASHBOTS_METHOD_SUFFIXES: &[&str] = &[ + "validateBuilderSubmissionV1", + "validateBuilderSubmissionV2", + "validateBuilderSubmissionV3", + "validateBuilderSubmissionV4", + "validateBuilderSubmissionV5", +]; + +/// All built-in namespaces and their method suffix slices. +pub const RPC_NAMESPACE_TABLE: &[(&str, &[&str])] = &[ + ("eth", ETH_METHOD_SUFFIXES), + ("net", NET_METHOD_SUFFIXES), + ("web3", WEB3_METHOD_SUFFIXES), + ("txpool", TXPOOL_METHOD_SUFFIXES), + ("rpc", RPC_API_METHOD_SUFFIXES), + ("admin", ADMIN_METHOD_SUFFIXES), + ("trace", TRACE_METHOD_SUFFIXES), + ("debug", DEBUG_METHOD_SUFFIXES), + ("engine", ENGINE_METHOD_SUFFIXES), + ("reth", RETH_METHOD_SUFFIXES), + ("ots", OTS_METHOD_SUFFIXES), + ("miner", MINER_METHOD_SUFFIXES), + ("mev", MEV_METHOD_SUFFIXES), + ("testing", TESTING_METHOD_SUFFIXES), + ("flashbots", FLASHBOTS_METHOD_SUFFIXES), + ("beradmin", BERA_ADMIN_METHOD_SUFFIXES), +]; + +/// Returns method suffixes for a namespace, or empty if unknown. +pub fn method_suffixes(namespace: &str) -> &[&str] { + for (name, suffixes) in RPC_NAMESPACE_TABLE { + if *name == namespace { + return suffixes; + } + } + &[] +} + +/// `namespace.method` strings for reedline tab completion. +pub fn dot_completions_for_namespace(namespace: &str) -> Vec { + method_suffixes(namespace).iter().map(|suffix| format!("{namespace}.{suffix}")).collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn eth_includes_common_methods() { + assert!(ETH_METHOD_SUFFIXES.contains(&"getLogs")); + assert!(ETH_METHOD_SUFFIXES.contains(&"blockNumber")); + } + + #[test] + fn unknown_namespace_empty() { + assert!(method_suffixes("not_a_real_ns").is_empty()); + } + + #[test] + fn table_covers_all_consts() { + let mut seen = 0usize; + for (name, suffixes) in RPC_NAMESPACE_TABLE { + assert!(!suffixes.is_empty(), "namespace {name} has no suffixes"); + seen += 1; + } + assert!(seen >= 10); + } + + #[test] + fn bera_admin_dot_forms() { + let v = dot_completions_for_namespace("beradmin"); + assert!(v.iter().any(|s| s == "beradmin.detailedPeers")); + assert!(v.iter().any(|s| s == "beradmin.sealedBlockAttribution")); + } +} diff --git a/src/console/run.rs b/src/console/run.rs new file mode 100644 index 00000000..d7f77a7d --- /dev/null +++ b/src/console/run.rs @@ -0,0 +1,51 @@ +use super::{ + cli::ConsoleCommand, + endpoint::resolve_endpoint, + exec::run_exec, + repl::{history_file_path, run_repl}, + rpc::RpcClient, +}; +use eyre::Result; +use serde_json::Value; + +pub async fn run_console(cmd: ConsoleCommand) -> Result<()> { + let endpoint = resolve_endpoint(cmd.endpoint.as_deref())?; + let rpc = RpcClient::connect(&endpoint).await?; + + let chain_id = + rpc.request_value("eth_chainId", None).await.ok().and_then(|v| parse_chain_id(&v)); + + let bera_admin_status = rpc.request_value("beradmin_nodeStatus", None).await.ok(); + let has_bera_admin = bera_admin_status.is_some(); + + if let Some(script) = cmd.exec.as_deref() { + run_exec(&rpc, script).await?; + } else { + run_repl( + &rpc, + history_file_path(), + endpoint, + chain_id, + cmd.raw, + has_bera_admin, + bera_admin_status, + ) + .await?; + } + + Ok(()) +} + +fn parse_chain_id(value: &Value) -> Option { + match value { + Value::String(s) => { + if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) { + u64::from_str_radix(hex, 16).ok() + } else { + s.parse().ok() + } + } + Value::Number(n) => n.as_u64(), + _ => None, + } +} diff --git a/src/engine/validator.rs b/src/engine/validator.rs index 5c8419a1..a183e418 100644 --- a/src/engine/validator.rs +++ b/src/engine/validator.rs @@ -162,8 +162,8 @@ where payload_or_attrs: PayloadOrAttributes<'_, Types::ExecutionData, Types::PayloadAttributes>, ) -> Result<(), EngineObjectValidationError> { // Validate execution requests if present in the payload - if let PayloadOrAttributes::ExecutionPayload(payload) = &payload_or_attrs && - let Some(requests) = payload.sidecar.requests() + if let PayloadOrAttributes::ExecutionPayload(payload) = &payload_or_attrs + && let Some(requests) = payload.sidecar.requests() { validate_execution_requests(requests)?; } diff --git a/src/evm/mod.rs b/src/evm/mod.rs index 34e441d9..dc829520 100644 --- a/src/evm/mod.rs +++ b/src/evm/mod.rs @@ -403,14 +403,14 @@ mod tests { assert!(result_without_tracer.is_ok()); // Both should have gas_used = 0 - if let Ok(result) = &result_with_tracer && - let ExecutionResult::Success { gas_used, .. } = &result.result + if let Ok(result) = &result_with_tracer + && let ExecutionResult::Success { gas_used, .. } = &result.result { assert_eq!(*gas_used, 0); } - if let Ok(result) = &result_without_tracer && - let ExecutionResult::Success { gas_used, .. } = &result.result + if let Ok(result) = &result_without_tracer + && let ExecutionResult::Success { gas_used, .. } = &result.result { assert_eq!(*gas_used, 0); } diff --git a/src/genesis/mod.rs b/src/genesis/mod.rs index a5e7a9ee..eb068c1d 100644 --- a/src/genesis/mod.rs +++ b/src/genesis/mod.rs @@ -98,12 +98,12 @@ impl TryFrom<&OtherFields> for BerachainGenesisConfig { (Some(prague1_config), Some(prague2_config)) => { // Both configured - validate Prague2 comes at or after Prague1 if prague2_config.time < prague1_config.time { - return Err(BerachainConfigError::InvalidConfig(serde_json::Error::io( - std::io::Error::new( + return Err(BerachainConfigError::InvalidConfig( + serde_json::Error::io(std::io::Error::new( std::io::ErrorKind::InvalidData, "Prague2 hardfork must activate at or after Prague1 hardfork", - ), - ))); + )), + )); } } _ => { diff --git a/src/hardforks/mod.rs b/src/hardforks/mod.rs index e42b9653..e80d963d 100644 --- a/src/hardforks/mod.rs +++ b/src/hardforks/mod.rs @@ -34,8 +34,8 @@ pub trait BerachainHardforks: EthereumHardforks { /// Checks if Prague3 hardfork is active at given timestamp /// Prague3 is active between its activation time and Prague4 activation fn is_prague3_active_at_timestamp(&self, timestamp: u64) -> bool { - self.berachain_fork_activation(BerachainHardfork::Prague3).active_at_timestamp(timestamp) && - !self.is_prague4_active_at_timestamp(timestamp) + self.berachain_fork_activation(BerachainHardfork::Prague3).active_at_timestamp(timestamp) + && !self.is_prague4_active_at_timestamp(timestamp) } /// Checks if Prague4 hardfork is active at given timestamp diff --git a/src/lib.rs b/src/lib.rs index 30b4118d..cc3d3e4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,10 @@ //! //! Built on Reth SDK with Ethereum compatibility plus Prague1 hardfork for minimum base fee. +pub mod berachain_cli; pub mod chainspec; pub mod consensus; +pub mod console; pub mod engine; pub mod evm; pub mod genesis; diff --git a/src/main.rs b/src/main.rs index d07ba485..77a8161c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator(); use bera_reth::{ + berachain_cli::BerachainSubcommands, chainspec::{BerachainChainSpec, BerachainChainSpecParser}, consensus::BerachainBeaconConsensus, evm::BerachainEvmFactory, @@ -13,9 +14,10 @@ use bera_reth::{ use clap::Parser; use reth::CliRunner; use reth_cli_commands::node::NoArgs; -use reth_ethereum_cli::Cli; +use reth_ethereum_cli::interface::{Cli, Commands}; use reth_node_builder::NodeHandle; -use std::sync::Arc; +use reth_rpc_server_types::DefaultRpcModuleValidator; +use std::{marker::PhantomData, sync::Arc}; use tracing::info; /// Persist every canonical block to disk immediately rather than buffering. @@ -47,20 +49,47 @@ fn main() { ) }; - if let Err(err) = Cli::::parse() - .with_runner_and_components::( - CliRunner::try_default_runtime().expect("Failed to create default runtime"), - cli_components_builder, - async move |builder, _| { - info!(target: "reth::cli", "Launching Berachain node"); - let NodeHandle { node: _node, node_exit_future } = - builder.node(BerachainNode::default()).launch_with_debug_capabilities().await?; + let cli = Cli::< + BerachainChainSpecParser, + NoArgs, + DefaultRpcModuleValidator, + BerachainSubcommands, + >::parse(); - node_exit_future.await - }, - ) - { - eprintln!("Error: {err:?}"); - std::process::exit(1); + let reth_ethereum_cli::interface::Cli { command, logs, traces, _phantom } = cli; + + match command { + Commands::Ext(BerachainSubcommands::Console(console_cmd)) => { + let runner = + CliRunner::try_default_runtime().expect("Failed to create default runtime"); + if let Err(err) = console_cmd.run(runner) { + eprintln!("Error: {err:?}"); + std::process::exit(1); + } + } + other => { + let cli = Cli { + command: other, + logs, + traces, + _phantom: PhantomData::, + }; + if let Err(err) = cli.with_runner_and_components::( + CliRunner::try_default_runtime().expect("Failed to create default runtime"), + cli_components_builder, + async move |builder, _| { + info!(target: "reth::cli", "Launching Berachain node"); + let NodeHandle { node: _node, node_exit_future } = builder + .node(BerachainNode::default()) + .launch_with_debug_capabilities() + .await?; + + node_exit_future.await + }, + ) { + eprintln!("Error: {err:?}"); + std::process::exit(1); + } + } } } diff --git a/src/pool/mod.rs b/src/pool/mod.rs index c3e491f0..f7da9247 100644 --- a/src/pool/mod.rs +++ b/src/pool/mod.rs @@ -39,8 +39,8 @@ where ) -> eyre::Result { let pool_config = ctx.pool_config(); - let blobs_disabled = ctx.config().txpool.disable_blobs_support || - ctx.config().txpool.blobpool_max_count == 0; + let blobs_disabled = ctx.config().txpool.disable_blobs_support + || ctx.config().txpool.blobpool_max_count == 0; let blob_cache_size = if let Some(blob_cache_size) = pool_config.blob_cache_size { Some(blob_cache_size) diff --git a/src/rpc/api.rs b/src/rpc/api.rs index 35817e31..59563d5e 100644 --- a/src/rpc/api.rs +++ b/src/rpc/api.rs @@ -226,16 +226,16 @@ impl TransactionBuilder for TransactionRequest { } fn can_submit(&self) -> bool { - self.from.is_some() && - self.to.is_some() && - self.gas.is_some() && - (self.gas_price.is_some() || self.max_fee_per_gas.is_some()) + self.from.is_some() + && self.to.is_some() + && self.gas.is_some() + && (self.gas_price.is_some() || self.max_fee_per_gas.is_some()) } fn can_build(&self) -> bool { - self.to.is_some() && - self.gas.is_some() && - (self.gas_price.is_some() || self.max_fee_per_gas.is_some()) + self.to.is_some() + && self.gas.is_some() + && (self.gas_price.is_some() || self.max_fee_per_gas.is_some()) } fn output_tx_type(&self) -> ::TxType { diff --git a/src/rpc/receipt.rs b/src/rpc/receipt.rs index b8c0a736..5d58e59b 100644 --- a/src/rpc/receipt.rs +++ b/src/rpc/receipt.rs @@ -74,24 +74,24 @@ impl BerachainReceiptEnvelope { /// Returns inner receipt reference pub const fn as_receipt(&self) -> &Receipt { match self { - Self::Legacy(receipt) | - Self::Eip2930(receipt) | - Self::Eip1559(receipt) | - Self::Eip4844(receipt) | - Self::Eip7702(receipt) | - Self::Berachain(receipt) => &receipt.receipt, + Self::Legacy(receipt) + | Self::Eip2930(receipt) + | Self::Eip1559(receipt) + | Self::Eip4844(receipt) + | Self::Eip7702(receipt) + | Self::Berachain(receipt) => &receipt.receipt, } } /// Returns the bloom filter for this receipt pub const fn bloom(&self) -> &Bloom { match self { - Self::Legacy(receipt) | - Self::Eip2930(receipt) | - Self::Eip1559(receipt) | - Self::Eip4844(receipt) | - Self::Eip7702(receipt) | - Self::Berachain(receipt) => &receipt.logs_bloom, + Self::Legacy(receipt) + | Self::Eip2930(receipt) + | Self::Eip1559(receipt) + | Self::Eip4844(receipt) + | Self::Eip7702(receipt) + | Self::Berachain(receipt) => &receipt.logs_bloom, } } } diff --git a/src/transaction/mod.rs b/src/transaction/mod.rs index 3387508d..97a2965e 100644 --- a/src/transaction/mod.rs +++ b/src/transaction/mod.rs @@ -138,13 +138,13 @@ impl PoLTx { } fn rlp_payload_length(&self) -> usize { - self.chain_id.length() + - self.from.length() + - self.to.length() + - self.nonce.length() + - self.gas_limit.length() + - self.gas_price.length() + - self.input.length() + self.chain_id.length() + + self.from.length() + + self.to.length() + + self.nonce.length() + + self.gas_limit.length() + + self.gas_price.length() + + self.input.length() } fn rlp_encoded_length(&self) -> usize {