From f46b63125d002cad444d40ad427bab120952003f Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 13 Jan 2026 12:10:50 -0500 Subject: [PATCH] feat(bin): kona consensus node --- Cargo.lock | 1964 +++++++++++++++++++++------- Cargo.toml | 42 +- bin/consensus/Cargo.toml | 16 + bin/consensus/src/cli.rs | 167 ++- bin/consensus/src/main.rs | 2 + crates/client/cli/Cargo.toml | 43 +- crates/client/cli/README.md | 8 +- crates/client/cli/src/boost.rs | 37 + crates/client/cli/src/builder.rs | 62 + crates/client/cli/src/config.rs | 145 ++ crates/client/cli/src/l2.rs | 27 +- crates/client/cli/src/lib.rs | 22 + crates/client/cli/src/p2p.rs | 754 +++++++++++ crates/client/cli/src/rpc.rs | 90 ++ crates/client/cli/src/sequencer.rs | 79 ++ crates/client/cli/src/signer.rs | 195 +++ deny.toml | 25 +- 17 files changed, 3174 insertions(+), 504 deletions(-) create mode 100644 crates/client/cli/src/boost.rs create mode 100644 crates/client/cli/src/builder.rs create mode 100644 crates/client/cli/src/config.rs create mode 100644 crates/client/cli/src/p2p.rs create mode 100644 crates/client/cli/src/rpc.rs create mode 100644 crates/client/cli/src/sequencer.rs create mode 100644 crates/client/cli/src/signer.rs diff --git a/Cargo.lock b/Cargo.lock index a8495096..25d2bb4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,9 +101,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e30ab0d3e3c32976f67fc1a96179989e45a69594af42003a6663332f9b0bb9d" +checksum = "12870ab65b131f609257436935047eec3cfabee8809732f6bf5a69fe2a18cf2e" dependencies = [ "alloy-eips", "alloy-primitives", @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20736b1f9d927d875d8777ef0c2250d4c57ea828529a9dbfa2c628db57b911e" +checksum = "47c66b14d2187de0c4efe4ef678aaa57a6a34cccdbea3a0773627fac9bd128f4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008aba161fce2a0d94956ae09d7d7a09f8fbdf18acbef921809ef126d6cdaf97" +checksum = "e9bf6afe8c25b63c98927c6f76d90cf8dc443cc4980a7d824151c84a6e568934" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b85157b7be31fc4adf6acfefcb0d4308cba5dbd7a8d8e62bcc02ff37d6131a" +checksum = "f076d25ddfcd2f1cbcc234e072baf97567d1df0e3fccdc1f8af8cc8b18dc6299" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -273,8 +273,8 @@ checksum = "527b47dc39850c6168002ddc1f7a2063e15d26137c1bb5330f6065a7524c1aa9" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.7", - "alloy-op-hardforks 0.4.7", + "alloy-hardforks", + "alloy-op-hardforks", "alloy-primitives", "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -290,9 +290,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a838301c4e2546c96db1848f18ffe9f722f2fccd9715b83d4bf269a2cf00b5a1" +checksum = "48d424ac007b5f89d65eecb4ed6cc5ca74cbaf231f471789a8158fdf4cc5f446" dependencies = [ "alloy-eips", "alloy-primitives", @@ -303,19 +303,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "alloy-hardforks" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165210652f71dfc094b051602bafd691f506c54050a174b1cba18fb5ef706a3" -dependencies = [ - "alloy-chains", - "alloy-eip2124", - "alloy-primitives", - "auto_impl", - "dyn-clone", -] - [[package]] name = "alloy-hardforks" version = "0.4.7" @@ -344,9 +331,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f045b69b5e80b8944b25afe74ae6b974f3044d84b4a7a113da04745b2524cc" +checksum = "250dbd8496f04eabe997e6e4c5186a0630b8bc3dbe7552e1fd917d491ef811e9" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -359,9 +346,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b314ed5bdc7f449c53853125af2db5ac4d3954a9f4b205e7d694f02fc1932d1" +checksum = "fd45cdac957d1fa1d0c18f54f262350eb72f1adc38dd1f8b15f33f0747c6a60c" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -385,9 +372,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9762ac5cca67b0f6ab614f7f8314942eead1c8eeef61511ea43a6ff048dbe0" +checksum = "fba5c43e055effb5bd33dbc74b1ab7fe0f367d8801a25af9e7c716b3ef5e440b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -405,7 +392,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-evm", - "alloy-op-hardforks 0.4.7", + "alloy-op-hardforks", "alloy-primitives", "auto_impl", "op-alloy-consensus", @@ -414,17 +401,6 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "alloy-op-hardforks" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3417f4187eaf7f7fb0d7556f0197bca26f0b23c4bb3aca0c9d566dc1c5d727a2" -dependencies = [ - "alloy-chains", - "alloy-hardforks 0.2.13", - "auto_impl", -] - [[package]] name = "alloy-op-hardforks" version = "0.4.7" @@ -432,7 +408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6472c610150c4c4c15be9e1b964c9b78068f933bda25fb9cdf09b9ac2bb66f36" dependencies = [ "alloy-chains", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "auto_impl", "serde", @@ -471,9 +447,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea8f7ca47514e7f552aa9f3f141ab17351332c6637e3bf00462d8e7c5f10f51f" +checksum = "9e87a90cacc27dffd91fa6440145934a782227d31b9876444c5924d3607084ea" dependencies = [ "alloy-chains", "alloy-consensus", @@ -515,9 +491,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4082778c908aa801a1f9fdc85d758812842ab4b2aaba58e9dbe7626d708ab7e1" +checksum = "c24a102935aa9d5a8b8fc8c47f39a0823672c33f0b27b5806292cb80988e6345" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -559,9 +535,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26dd083153d2cb73cce1516f5a3f9c3af74764a2761d901581a355777468bd8f" +checksum = "57a65bb9060e43e9738bbd7c30d742ed962d609f2123a665bbdab7e6e0f13fd3" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -585,9 +561,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c998214325cfee1fbe61e5abaed3a435f4ca746ac7399b46feb57c364552452" +checksum = "98bfd40f4e36cb29015ec744bc764629edbe823ec6b95aceef2684090c142976" dependencies = [ "alloy-primitives", "alloy-rpc-types-engine", @@ -598,9 +574,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-admin" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730a38742dc0753f25b8ce7330c2fa88d79f165c5fc2f19f3d35291739c42e83" +checksum = "89123971b8e640d2841150680fba6cdeedbee483ae15d4b0bc3f1507f4715eb1" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -610,9 +586,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b03d65fcf579fbf17d3aac32271f99e2b562be04097436cd6e766b3e06613b" +checksum = "1ac7d0dbb62e807028554e34c2b5724a1f57132792684107c32009e84fcf4044" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -622,9 +598,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4a6f49d161ef83354d5ba3c8bc83c8ee464cb90182b215551d5c4b846579be" +checksum = "8faa6f22068857f58579271b15e042f4725ad35cdce2ed4778ba32ffd3102b92" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -633,9 +609,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6654644613f33fd2e6f333f4ce8ad0a26f036c0513699d7bc168bba18d412d" +checksum = "2ff8cc4b56836a9ffb4b19c3a221bba64e497199bf3900c302aee493a50dadb8" dependencies = [ "alloy-eips", "alloy-primitives", @@ -653,9 +629,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467025b916f32645f322a085d0017f2996d0200ac89dd82a4fc2bf0f17b9afa3" +checksum = "ccb37a9eee8e7a19bb07b5cd55d33457884e44b212588b7429c5d318d2b90295" dependencies = [ "alloy-primitives", "derive_more", @@ -665,9 +641,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "933aaaace9faa6d7efda89472add89a8bfd15270318c47a2be8bb76192c951e2" +checksum = "95157286826aa7bb5463a5f4188266bbf2555db1fd53bb814a4b35c106f2a498" dependencies = [ "alloy-consensus", "alloy-eips", @@ -685,9 +661,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11920b16ab7c86052f990dcb4d25312fb2889faf506c4ee13dc946b450536989" +checksum = "1ec734cce11f7fe889950b36b51589397528b26beb6f890834a2131ee9f174d7" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -707,9 +683,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-mev" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1826454c2890af6d642bf052909e0162ad7f261d172e56ef2e936d479960699c" +checksum = "6ddbe530062af75ec960fae36dcd1e5596615b730c83c535ecd9d3ec113ef3d7" dependencies = [ "alloy-consensus", "alloy-eips", @@ -722,9 +698,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "498375e6a13b6edd04422a13d2b1a6187183e5a3aa14c5907b4c566551248bab" +checksum = "7fe64cd4af2e68b2154ac02a7908249a448fbd3d1d05890786a5af93686083cc" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -736,9 +712,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9123d321ecd70925646eb2c60b1d9b7a965f860fbd717643e2c20fcf85d48d" +checksum = "9504c0f00a72883e640abc4681a5691a57dec693bc28d4aa80257c8e1e9e6e1f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -748,9 +724,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a0d2d5c64881f3723232eaaf6c2d9f4f88b061c63e87194b2db785ff3aa31f" +checksum = "27f076bfd74fccc63d50546e1765359736357a953de2eb778b7b6191571735e6" dependencies = [ "alloy-primitives", "arbitrary", @@ -760,9 +736,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea4ac9765e5a7582877ca53688e041fe184880fe75f16edf0945b24a319c710" +checksum = "d80748c209a68421ab6f737828ce6ede7543569a5cad099c1ec16fc1baa05620" dependencies = [ "alloy-primitives", "async-trait", @@ -775,9 +751,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9d85b9f7105ab5ce7dae7b0da33cd9d977601a48f759e1c82958978dd1a905" +checksum = "17eb1eb39351b4bf20bb0710d8d3a91eb7918d3f3de2f3835f556842e33865cb" dependencies = [ "alloy-consensus", "alloy-network", @@ -867,9 +843,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e72f5c4ba505ebead6a71144d72f21a70beadfb2d84e0a560a985491ecb71de" +checksum = "4a0c1a0288cdff6ee2b2c2c98ab42889d221ca8a9ee4120ede59b5449e0dcb20" dependencies = [ "alloy-json-rpc", "auto_impl", @@ -890,9 +866,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "400dc298aaabdbd48be05448c4a19eaa38416c446043f3e54561249149269c32" +checksum = "36dfa207caf6b528b9466c714626f5b2dfd5e8d4595a74631d5670672dac102b" dependencies = [ "alloy-json-rpc", "alloy-rpc-types-engine", @@ -914,9 +890,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba22ff961cf99495ee4fdbaf4623f8d5483d408ca2c6e1b1a54ef438ca87f8dd" +checksum = "bf45686199d20b395d5912163f8fe497853b7f13de110bd552e50a0447bb4f48" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -934,9 +910,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c38b4472f2bbd96a27f393de9e2f12adca0dc1075fb4d0f7c8f3557c5c600392" +checksum = "91620efb46f8d011e37f74fac53a643e830a7bb24982143094b887003cbfb6be" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -971,9 +947,9 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2183706e24173309b0ab0e34d3e53cf3163b71a419803b2b3b0c1fb7ff7a941" +checksum = "bb0d567f4830dea921868c7680004ae0c7f221b05e6477db6c077c7953698f56" dependencies = [ "darling 0.21.3", "proc-macro2", @@ -1389,6 +1365,45 @@ dependencies = [ "serde", ] +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.17", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "asn1_der" version = "0.7.6" @@ -1405,6 +1420,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compression" version = "0.4.37" @@ -1417,6 +1444,24 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 1.1.3", + "slab", + "windows-sys 0.61.2", +] + [[package]] name = "async-lock" version = "3.4.2" @@ -1482,12 +1527,37 @@ dependencies = [ "rustc_version 0.4.1", ] +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attohttpc" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" +dependencies = [ + "base64 0.22.1", + "http", + "log", + "url", +] + [[package]] name = "aurora-engine-modexp" version = "1.2.0" @@ -1688,8 +1758,35 @@ dependencies = [ name = "base-client-cli" version = "0.0.0" dependencies = [ - "alloy-rpc-types-engine", + "alloy-chains", + "alloy-primitives", + "alloy-provider", + "alloy-signer", + "alloy-signer-local", + "base-jwt", "clap", + "discv5", + "eyre", + "kona-cli", + "kona-derive", + "kona-disc", + "kona-engine", + "kona-genesis", + "kona-gossip", + "kona-node-service", + "kona-peers", + "kona-providers-alloy", + "kona-registry", + "kona-rpc", + "kona-sources", + "libp2p", + "reqwest", + "rollup-boost", + "rstest", + "serde_json", + "thiserror 2.0.17", + "tokio", + "tracing", "url", ] @@ -1739,9 +1836,19 @@ name = "base-consensus" version = "0.0.0" dependencies = [ "base-cli-utils", + "base-client-cli", "clap", "eyre", + "kona-derive", + "kona-disc", + "kona-engine", + "kona-gossip", + "kona-node-service", + "kona-providers-alloy", "metrics", + "strum 0.27.2", + "tracing", + "tracing-subscriber 0.3.22", "vergen", "vergen-git2", ] @@ -1802,7 +1909,7 @@ dependencies = [ "reth-tracing", "reth-transaction-pool", "revm 31.0.2", - "revm-database 9.0.6", + "revm-database", "rstest", "serde", "serde_json", @@ -1880,7 +1987,7 @@ dependencies = [ "reth-revm", "reth-transaction-pool", "reth-trie-common", - "revm-database 9.0.6", + "revm-database", "serde", "tokio", "tracing", @@ -2133,6 +2240,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -2435,6 +2551,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "chrono" version = "0.4.42" @@ -2484,6 +2624,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -3180,6 +3321,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.5" @@ -3422,6 +3577,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + [[package]] name = "dtor" version = "0.0.6" @@ -3881,6 +4042,16 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-bounded" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e" +dependencies = [ + "futures-timer", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -3906,6 +4077,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -3914,6 +4086,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -3925,6 +4107,17 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -4268,6 +4461,12 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + [[package]] name = "hickory-proto" version = "0.25.2" @@ -4287,6 +4486,7 @@ dependencies = [ "rand 0.9.2", "ring", "serde", + "socket2 0.5.10", "thiserror 2.0.17", "tinyvec", "tokio", @@ -4710,6 +4910,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "if-addrs" version = "0.14.0" @@ -4721,8 +4931,52 @@ dependencies = [ ] [[package]] -name = "impl-codec" -version = "0.6.0" +name = "if-watch" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" +dependencies = [ + "async-io", + "core-foundation 0.9.4", + "fnv", + "futures", + "if-addrs 0.10.2", + "ipnet", + "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-proto", + "netlink-sys", + "rtnetlink", + "system-configuration", + "tokio", + "windows 0.53.0", +] + +[[package]] +name = "igd-next" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516893339c97f6011282d5825ac94fc1c7aad5cad26bdc2d0cee068c0bf97f97" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http", + "http-body-util", + "hyper", + "hyper-util", + "log", + "rand 0.9.2", + "tokio", + "url", + "xmltree", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ @@ -4882,6 +5136,9 @@ name = "ipnet" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +dependencies = [ + "serde", +] [[package]] name = "iri-string" @@ -5215,6 +5472,69 @@ dependencies = [ "sha3-asm", ] +[[package]] +name = "kona-cli" +version = "0.3.2" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-chains", + "alloy-primitives", + "clap", + "kona-genesis", + "kona-registry", + "libc", + "libp2p", + "metrics-exporter-prometheus 0.18.1", + "metrics-process", + "serde", + "thiserror 2.0.17", + "tracing", + "tracing-appender", + "tracing-subscriber 0.3.22", +] + +[[package]] +name = "kona-derive" +version = "0.4.5" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-engine", + "async-trait", + "kona-genesis", + "kona-hardforks", + "kona-macros", + "kona-protocol", + "metrics", + "op-alloy-consensus", + "op-alloy-rpc-types-engine", + "thiserror 2.0.17", + "tracing", +] + +[[package]] +name = "kona-disc" +version = "0.1.2" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-rlp", + "backon", + "derive_more", + "discv5", + "kona-genesis", + "kona-macros", + "kona-peers", + "libp2p", + "metrics", + "rand 0.9.2", + "thiserror 2.0.17", + "tokio", + "tracing", +] + [[package]] name = "kona-engine" version = "0.1.2" @@ -5236,9 +5556,10 @@ dependencies = [ "http", "http-body-util", "jsonrpsee-types", - "kona-genesis 0.4.5 (git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d)", + "kona-genesis", "kona-macros", "kona-protocol", + "metrics", "op-alloy-consensus", "op-alloy-network", "op-alloy-provider", @@ -5257,41 +5578,66 @@ dependencies = [ [[package]] name = "kona-genesis" version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b122a661c9f5efca5783f56674383eb742472796d2d4cf3d12a803b37f6bb11b" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" dependencies = [ "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.2.13", - "alloy-op-hardforks 0.2.13", + "alloy-genesis", + "alloy-hardforks", + "alloy-op-hardforks", "alloy-primitives", "alloy-sol-types", "derive_more", - "op-revm 8.1.0", + "op-revm 14.1.0", "serde", "serde_repr", "thiserror 2.0.17", ] [[package]] -name = "kona-genesis" -version = "0.4.5" +name = "kona-gossip" +version = "0.1.2" source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" dependencies = [ - "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-genesis", - "alloy-hardforks 0.4.7", - "alloy-op-hardforks 0.4.7", "alloy-primitives", - "alloy-sol-types", + "alloy-rlp", + "alloy-rpc-types-engine", "derive_more", - "op-revm 14.1.0", + "discv5", + "futures", + "ipnet", + "kona-disc", + "kona-genesis", + "kona-macros", + "kona-peers", + "lazy_static", + "libp2p", + "libp2p-identity", + "libp2p-stream", + "metrics", + "op-alloy-consensus", + "op-alloy-rpc-types-engine", + "openssl", "serde", "serde_repr", + "snap", "thiserror 2.0.17", + "tokio", + "tracing", +] + +[[package]] +name = "kona-hardforks" +version = "0.4.5" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "kona-protocol", + "op-alloy-consensus", ] [[package]] @@ -5299,6 +5645,81 @@ name = "kona-macros" version = "0.1.2" source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +[[package]] +name = "kona-node-service" +version = "0.1.3" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-chains", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "backon", + "derive_more", + "discv5", + "futures", + "http-body-util", + "jsonrpsee", + "kona-derive", + "kona-disc", + "kona-engine", + "kona-genesis", + "kona-gossip", + "kona-macros", + "kona-peers", + "kona-protocol", + "kona-providers-alloy", + "kona-rpc", + "kona-sources", + "libp2p", + "libp2p-stream", + "metrics", + "op-alloy-network", + "op-alloy-provider", + "op-alloy-rpc-types-engine", + "rollup-boost", + "strum 0.27.2", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tokio-util", + "tower 0.5.3", + "tracing", + "url", +] + +[[package]] +name = "kona-peers" +version = "0.1.2" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "derive_more", + "dirs", + "discv5", + "kona-registry", + "lazy_static", + "libp2p", + "libp2p-identity", + "secp256k1 0.31.1", + "serde", + "serde_json", + "thiserror 2.0.17", + "tracing", + "unsigned-varint 0.8.0", + "url", +] + [[package]] name = "kona-protocol" version = "0.4.5" @@ -5307,7 +5728,7 @@ dependencies = [ "alloc-no-stdlib", "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -5316,7 +5737,7 @@ dependencies = [ "async-trait", "brotli", "derive_more", - "kona-genesis 0.4.5 (git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d)", + "kona-genesis", "miniz_oxide", "op-alloy-consensus", "op-alloy-rpc-types", @@ -5326,23 +5747,113 @@ dependencies = [ "thiserror 2.0.17", "tracing", "tracing-subscriber 0.3.22", - "unsigned-varint", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "kona-providers-alloy" +version = "0.3.3" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types-beacon", + "alloy-rpc-types-engine", + "alloy-serde", + "alloy-transport", + "alloy-transport-http", + "async-trait", + "c-kzg", + "http-body-util", + "kona-derive", + "kona-genesis", + "kona-macros", + "kona-protocol", + "lru 0.16.3", + "metrics", + "op-alloy-consensus", + "op-alloy-network", + "reqwest", + "serde", + "thiserror 2.0.17", + "tower 0.5.3", ] [[package]] name = "kona-registry" version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bfcd0cdb9e3ef882d403dd33f11e9d6a203ce8e00d333b14792454bd7e01de" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" dependencies = [ "alloy-chains", - "alloy-op-hardforks 0.2.13", + "alloy-eips", + "alloy-genesis", + "alloy-hardforks", + "alloy-op-hardforks", "alloy-primitives", - "kona-genesis 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "kona-genesis", "lazy_static", "serde", "serde_json", - "toml", + "toml 0.9.11+spec-1.1.0", +] + +[[package]] +name = "kona-rpc" +version = "0.3.2" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rpc-types-engine", + "async-trait", + "backon", + "derive_more", + "getrandom 0.3.4", + "ipnet", + "jsonrpsee", + "kona-engine", + "kona-genesis", + "kona-gossip", + "kona-macros", + "kona-protocol", + "libp2p", + "metrics", + "op-alloy-consensus", + "op-alloy-rpc-jsonrpsee", + "op-alloy-rpc-types", + "op-alloy-rpc-types-engine", + "rollup-boost", + "serde", + "thiserror 2.0.17", + "tokio", + "tracing", +] + +[[package]] +name = "kona-sources" +version = "0.1.2" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-primitives", + "alloy-rpc-client", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", + "derive_more", + "notify", + "op-alloy-rpc-types-engine", + "reqwest", + "rustls", + "serde", + "serde_json", + "thiserror 2.0.17", + "tokio", + "tracing", + "url", ] [[package]] @@ -5366,71 +5877,429 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libgit2-sys" +version = "0.18.3+1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libp2p" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce71348bf5838e46449ae240631117b487073d5f347c06d434caddcb91dceb5a" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom 0.2.17", + "libp2p-allow-block-list", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-dns", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-identity", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-noise", + "libp2p-ping", + "libp2p-quic", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-upnp", + "libp2p-yamux", + "multiaddr", + "pin-project", + "rw-stream-sink", + "thiserror 2.0.17", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16ccf824ee859ca83df301e1c0205270206223fd4b1f2e512a693e1912a8f4a" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18b8b607cf3bfa2f8c57db9c7d8569a315d5cc0a282e6bfd5ebfc0a9840b2a0" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", +] + +[[package]] +name = "libp2p-core" +version = "0.43.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "249128cd37a2199aff30a7675dffa51caf073b51aa612d2f544b19932b9aebca" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr", + "multihash", + "multistream-select", + "parking_lot", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink", + "thiserror 2.0.17", + "tracing", + "unsigned-varint 0.8.0", + "web-time", +] + +[[package]] +name = "libp2p-dns" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b770c1c8476736ca98c578cba4b505104ff8e842c2876b528925f9766379f9a" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.49.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f58e37d8d6848e5c4c9e3c35c6f61133235bff2960c9c00a663b0849301221" +dependencies = [ + "async-channel", + "asynchronous-codec", + "base64 0.22.1", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-timer", + "getrandom 0.2.17", + "hashlink", + "hex_fmt", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.5", + "regex", + "sha2", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-identify" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ab792a8b68fdef443a62155b01970c81c3aadab5e659621b063ef252a8e65e8" +dependencies = [ + "asynchronous-codec", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "quick-protobuf", + "quick-protobuf-codec", + "smallvec", + "thiserror 2.0.17", + "tracing", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c7892c221730ba55f7196e98b0b8ba5e04b4155651736036628e9f73ed6fc3" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "hkdf", + "k256", + "multihash", + "quick-protobuf", + "rand 0.8.5", + "sha2", + "thiserror 2.0.17", + "tracing", + "zeroize", +] + +[[package]] +name = "libp2p-mdns" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66872d0f1ffcded2788683f76931be1c52e27f343edb93bc6d0bcd8887be443" +dependencies = [ + "futures", + "hickory-proto", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "smallvec", + "socket2 0.5.10", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-metrics" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805a555148522cb3414493a5153451910cb1a146c53ffbf4385708349baf62b7" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-identity", + "libp2p-ping", + "libp2p-swarm", + "pin-project", + "prometheus-client", + "web-time", +] + +[[package]] +name = "libp2p-noise" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc73eacbe6462a0eb92a6527cac6e63f02026e5407f8831bde8293f19217bfbf" +dependencies = [ + "asynchronous-codec", + "bytes", + "futures", + "libp2p-core", + "libp2p-identity", + "multiaddr", + "multihash", + "quick-protobuf", + "rand 0.8.5", + "snow", + "static_assertions", + "thiserror 2.0.17", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "libp2p-ping" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74bb7fcdfd9fead4144a3859da0b49576f171a8c8c7c0bfc7c541921d25e60d3" +dependencies = [ + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-quic" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc448b2de9f4745784e3751fe8bc6c473d01b8317edd5ababcb0dec803d843f" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "quinn", + "rand 0.8.5", + "ring", + "rustls", + "socket2 0.5.10", + "thiserror 2.0.17", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-stream" +version = "0.4.0-alpha" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "1d6bd8025c80205ec2810cfb28b02f362ab48a01bee32c50ab5f12761e033464" dependencies = [ - "spin 0.9.8", + "futures", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "tracing", ] [[package]] -name = "lazycell" -version = "1.3.0" +name = "libp2p-swarm" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "6aa762e5215919a34e31c35d4b18bf2e18566ecab7f8a3d39535f4a3068f8b62" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm-derive", + "lru 0.12.5", + "multistream-select", + "rand 0.8.5", + "smallvec", + "tokio", + "tracing", + "web-time", +] [[package]] -name = "libc" -version = "0.2.180" +name = "libp2p-swarm-derive" +version = "0.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "dd297cf53f0cb3dee4d2620bb319ae47ef27c702684309f682bdb7e55a18ae9c" +dependencies = [ + "heck", + "quote", + "syn 2.0.114", +] [[package]] -name = "libgit2-sys" -version = "0.18.3+1.9.2" +name = "libp2p-tcp" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +checksum = "65b4e030c52c46c8d01559b2b8ca9b7c4185f10576016853129ca1fe5cd1a644" dependencies = [ - "cc", + "futures", + "futures-timer", + "if-watch", "libc", - "libz-sys", - "pkg-config", + "libp2p-core", + "socket2 0.5.10", + "tokio", + "tracing", ] [[package]] -name = "libloading" -version = "0.8.9" +name = "libp2p-tls" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +checksum = "96ff65a82e35375cbc31ebb99cacbbf28cb6c4fefe26bf13756ddcf708d40080" dependencies = [ - "cfg-if", - "windows-link", + "futures", + "futures-rustls", + "libp2p-core", + "libp2p-identity", + "rcgen", + "ring", + "rustls", + "rustls-webpki", + "thiserror 2.0.17", + "x509-parser", + "yasna", ] [[package]] -name = "libm" -version = "0.2.15" +name = "libp2p-upnp" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "4757e65fe69399c1a243bbb90ec1ae5a2114b907467bf09f3575e899815bb8d3" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core", + "libp2p-swarm", + "tokio", + "tracing", +] [[package]] -name = "libp2p-identity" -version = "0.2.13" +name = "libp2p-yamux" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c7892c221730ba55f7196e98b0b8ba5e04b4155651736036628e9f73ed6fc3" +checksum = "f15df094914eb4af272acf9adaa9e287baa269943f32ea348ba29cfb9bfc60d8" dependencies = [ - "asn1_der", - "bs58", - "ed25519-dalek", - "hkdf", - "k256", - "multihash", - "quick-protobuf", - "sha2", + "either", + "futures", + "libp2p-core", "thiserror 2.0.17", "tracing", - "zeroize", + "yamux 0.12.1", + "yamux 0.13.8", ] [[package]] @@ -5879,7 +6748,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.8.0", "url", ] @@ -5902,7 +6771,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ "core2", - "unsigned-varint", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", ] [[package]] @@ -5931,6 +6814,70 @@ dependencies = [ "tempfile", ] +[[package]] +name = "netlink-packet-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +dependencies = [ + "anyhow", + "byteorder", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror 1.0.69", +] + +[[package]] +name = "netlink-proto" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72452e012c2f8d612410d89eea01e2d9b56205274abb35d53f60200b2ec41d60" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror 2.0.17", +] + +[[package]] +name = "netlink-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -5940,6 +6887,23 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -6128,6 +7092,15 @@ dependencies = [ "smallvec", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -6390,18 +7363,6 @@ dependencies = [ "vergen-git2", ] -[[package]] -name = "op-revm" -version = "8.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce1dc7533f4e5716c55cd3d62488c6200cb4dfda96e0c75a7e484652464343b" -dependencies = [ - "auto_impl", - "once_cell", - "revm 27.1.0", - "serde", -] - [[package]] name = "op-revm" version = "12.0.2" @@ -6468,6 +7429,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +[[package]] +name = "openssl-src" +version = "300.5.4+3.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.111" @@ -6476,6 +7446,7 @@ checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -6828,38 +7799,17 @@ dependencies = [ "rustc_version 0.4.1", ] -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", - "serde", -] - [[package]] name = "phf" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_macros 0.13.1", - "phf_shared 0.13.1", + "phf_macros", + "phf_shared", "serde", ] -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - [[package]] name = "phf_generator" version = "0.13.1" @@ -6867,20 +7817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.114", + "phf_shared", ] [[package]] @@ -6889,22 +7826,13 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", "syn 2.0.114", ] -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - [[package]] name = "phf_shared" version = "0.13.1" @@ -6999,6 +7927,31 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 1.1.3", + "windows-sys 0.61.2", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "polyval" version = "0.6.2" @@ -7167,6 +8120,29 @@ dependencies = [ "hex", ] +[[package]] +name = "prometheus-client" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf41c1a7c32ed72abe5082fb19505b969095c12da9f5732a4bc9878757fd087c" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "proptest" version = "1.9.0" @@ -7305,6 +8281,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec", + "bytes", + "quick-protobuf", + "thiserror 1.0.69", + "unsigned-varint 0.8.0", +] + [[package]] name = "quinn" version = "0.11.9" @@ -7313,6 +8302,7 @@ checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", + "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -7531,6 +8521,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna", +] + [[package]] name = "recvmsg" version = "1.0.0" @@ -7743,8 +8746,8 @@ dependencies = [ "reth-primitives-traits", "reth-storage-api", "reth-trie", - "revm-database 9.0.6", - "revm-state 8.1.1", + "revm-database", + "revm-state", "serde", "tokio", "tokio-stream", @@ -7855,7 +8858,7 @@ dependencies = [ "tar", "tokio", "tokio-stream", - "toml", + "toml 0.8.23", "tracing", "zstd", ] @@ -7929,7 +8932,7 @@ dependencies = [ "reth-prune-types", "reth-stages-types", "serde", - "toml", + "toml 0.8.23", "url", ] @@ -8398,7 +9401,7 @@ dependencies = [ "reth-trie-sparse", "reth-trie-sparse-parallel", "revm 31.0.2", - "revm-primitives 21.0.2", + "revm-primitives", "schnellru", "smallvec", "thiserror 2.0.17", @@ -8534,7 +9537,7 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "alloy-rlp", "bytes", @@ -8587,7 +9590,7 @@ version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ "alloy-eip2124", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "arbitrary", "auto_impl", @@ -8812,8 +9815,8 @@ dependencies = [ "reth-tracing", "reth-trie", "revm 31.0.2", - "revm-bytecode 7.1.1", - "revm-database 9.0.6", + "revm-bytecode", + "revm-database", "serde", "serde_json", ] @@ -8889,7 +9892,7 @@ version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ "futures-util", - "if-addrs", + "if-addrs 0.14.0", "reqwest", "serde_with", "thiserror 2.0.17", @@ -9184,7 +10187,7 @@ dependencies = [ "shellexpand", "strum 0.27.2", "thiserror 2.0.17", - "toml", + "toml 0.8.23", "tracing", "url", "vergen", @@ -9320,7 +10323,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "derive_more", "miniz_oxide", @@ -9486,7 +10489,7 @@ name = "reth-optimism-forks" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-op-hardforks 0.4.7", + "alloy-op-hardforks", "alloy-primitives", "once_cell", "reth-ethereum-forks", @@ -9820,9 +10823,9 @@ dependencies = [ "proptest-arbitrary-interop", "rayon", "reth-codecs", - "revm-bytecode 7.1.1", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-bytecode", + "revm-primitives", + "revm-state", "secp256k1 0.30.0", "serde", "serde_with", @@ -9866,8 +10869,8 @@ dependencies = [ "reth-storage-errors", "reth-trie", "reth-trie-db", - "revm-database 9.0.6", - "revm-state 8.1.1", + "revm-database", + "revm-state", "strum 0.27.2", "tokio", "tracing", @@ -9995,7 +10998,7 @@ dependencies = [ "reth-trie-common", "revm 31.0.2", "revm-inspectors", - "revm-primitives 21.0.2", + "revm-primitives", "serde", "serde_json", "sha2", @@ -10393,7 +11396,7 @@ dependencies = [ "reth-stages-types", "reth-storage-errors", "reth-trie-common", - "revm-database 9.0.6", + "revm-database", ] [[package]] @@ -10408,7 +11411,7 @@ dependencies = [ "reth-primitives-traits", "reth-prune-types", "reth-static-file-types", - "revm-database-interface 8.0.5", + "revm-database-interface", "thiserror 2.0.17", ] @@ -10519,7 +11522,7 @@ dependencies = [ "reth-storage-api", "reth-tasks", "revm-interpreter 29.0.1", - "revm-primitives 21.0.2", + "revm-primitives", "rustc-hash 2.1.1", "schnellru", "serde", @@ -10551,7 +11554,7 @@ dependencies = [ "reth-storage-errors", "reth-trie-common", "reth-trie-sparse", - "revm-database 9.0.6", + "revm-database", "tracing", "triehash", ] @@ -10578,7 +11581,7 @@ dependencies = [ "rayon", "reth-codecs", "reth-primitives-traits", - "revm-database 9.0.6", + "revm-database", "serde", "serde_with", ] @@ -10666,42 +11669,23 @@ dependencies = [ "zstd", ] -[[package]] -name = "revm" -version = "27.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6bf82101a1ad8a2b637363a37aef27f88b4efc8a6e24c72bf5f64923dc5532" -dependencies = [ - "revm-bytecode 6.2.2", - "revm-context 8.0.4", - "revm-context-interface 9.0.0", - "revm-database 7.0.5", - "revm-database-interface 7.0.5", - "revm-handler 8.1.0", - "revm-inspector 8.1.0", - "revm-interpreter 24.0.0", - "revm-precompile 25.0.0", - "revm-primitives 20.2.1", - "revm-state 7.0.5", -] - [[package]] name = "revm" version = "31.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb67a5223602113cae59a305acde2d9936bc18f2478dda879a6124b267cebfb6" dependencies = [ - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context 11.0.2", "revm-context-interface 12.0.1", - "revm-database 9.0.6", - "revm-database-interface 8.0.5", + "revm-database", + "revm-database-interface", "revm-handler 12.0.2", "revm-inspector 12.0.2", "revm-interpreter 29.0.1", "revm-precompile 29.0.1", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-primitives", + "revm-state", ] [[package]] @@ -10710,29 +11694,17 @@ version = "33.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c85ed0028f043f87b3c88d4a4cb6f0a76440085523b6a8afe5ff003cf418054" dependencies = [ - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context 12.1.0", "revm-context-interface 13.1.0", - "revm-database 9.0.6", - "revm-database-interface 8.0.5", + "revm-database", + "revm-database-interface", "revm-handler 14.1.0", "revm-inspector 14.1.0", "revm-interpreter 31.1.0", "revm-precompile 31.0.0", - "revm-primitives 21.0.2", - "revm-state 8.1.1", -] - -[[package]] -name = "revm-bytecode" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c52031b73cae95d84cd1b07725808b5fd1500da3e5e24574a3b2dc13d9f16d" -dependencies = [ - "bitvec", - "phf 0.11.3", - "revm-primitives 20.2.1", - "serde", + "revm-primitives", + "revm-state", ] [[package]] @@ -10742,24 +11714,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2c6b5e6e8dd1e28a4a60e5f46615d4ef0809111c9e63208e55b5c7058200fb0" dependencies = [ "bitvec", - "phf 0.13.1", - "revm-primitives 21.0.2", - "serde", -] - -[[package]] -name = "revm-context" -version = "8.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd508416a35a4d8a9feaf5ccd06ac6d6661cd31ee2dc0252f9f7316455d71f9" -dependencies = [ - "cfg-if", - "derive-where", - "revm-bytecode 6.2.2", - "revm-context-interface 9.0.0", - "revm-database-interface 7.0.5", - "revm-primitives 20.2.1", - "revm-state 7.0.5", + "phf", + "revm-primitives", "serde", ] @@ -10772,11 +11728,11 @@ dependencies = [ "bitvec", "cfg-if", "derive-where", - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context-interface 12.0.1", - "revm-database-interface 8.0.5", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-database-interface", + "revm-primitives", + "revm-state", "serde", ] @@ -10789,27 +11745,11 @@ dependencies = [ "bitvec", "cfg-if", "derive-where", - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context-interface 13.1.0", - "revm-database-interface 8.0.5", - "revm-primitives 21.0.2", - "revm-state 8.1.1", - "serde", -] - -[[package]] -name = "revm-context-interface" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc90302642d21c8f93e0876e201f3c5f7913c4fcb66fb465b0fd7b707dfe1c79" -dependencies = [ - "alloy-eip2930", - "alloy-eip7702", - "auto_impl", - "either", - "revm-database-interface 7.0.5", - "revm-primitives 20.2.1", - "revm-state 7.0.5", + "revm-database-interface", + "revm-primitives", + "revm-state", "serde", ] @@ -10823,9 +11763,9 @@ dependencies = [ "alloy-eip7702", "auto_impl", "either", - "revm-database-interface 8.0.5", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-database-interface", + "revm-primitives", + "revm-state", "serde", ] @@ -10839,23 +11779,9 @@ dependencies = [ "alloy-eip7702", "auto_impl", "either", - "revm-database-interface 8.0.5", - "revm-primitives 21.0.2", - "revm-state 8.1.1", - "serde", -] - -[[package]] -name = "revm-database" -version = "7.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a276ed142b4718dcf64bc9624f474373ed82ef20611025045c3fb23edbef9c" -dependencies = [ - "alloy-eips", - "revm-bytecode 6.2.2", - "revm-database-interface 7.0.5", - "revm-primitives 20.2.1", - "revm-state 7.0.5", + "revm-database-interface", + "revm-primitives", + "revm-state", "serde", ] @@ -10866,23 +11792,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "980d8d6bba78c5dd35b83abbb6585b0b902eb25ea4448ed7bfba6283b0337191" dependencies = [ "alloy-eips", - "revm-bytecode 7.1.1", - "revm-database-interface 8.0.5", - "revm-primitives 21.0.2", - "revm-state 8.1.1", - "serde", -] - -[[package]] -name = "revm-database-interface" -version = "7.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c523c77e74eeedbac5d6f7c092e3851dbe9c7fec6f418b85992bd79229db361" -dependencies = [ - "auto_impl", - "either", - "revm-primitives 20.2.1", - "revm-state 7.0.5", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", "serde", ] @@ -10894,27 +11807,8 @@ checksum = "8cce03e3780287b07abe58faf4a7f5d8be7e81321f93ccf3343c8f7755602bae" dependencies = [ "auto_impl", "either", - "revm-primitives 21.0.2", - "revm-state 8.1.1", - "serde", -] - -[[package]] -name = "revm-handler" -version = "8.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1529c8050e663be64010e80ec92bf480315d21b1f2dbf65540028653a621b27d" -dependencies = [ - "auto_impl", - "derive-where", - "revm-bytecode 6.2.2", - "revm-context 8.0.4", - "revm-context-interface 9.0.0", - "revm-database-interface 7.0.5", - "revm-interpreter 24.0.0", - "revm-precompile 25.0.0", - "revm-primitives 20.2.1", - "revm-state 7.0.5", + "revm-primitives", + "revm-state", "serde", ] @@ -10926,14 +11820,14 @@ checksum = "b45418ed95cfdf0cb19effdbb7633cf2144cab7fb0e6ffd6b0eb9117a50adff6" dependencies = [ "auto_impl", "derive-where", - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context 11.0.2", "revm-context-interface 12.0.1", - "revm-database-interface 8.0.5", + "revm-database-interface", "revm-interpreter 29.0.1", "revm-precompile 29.0.1", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-primitives", + "revm-state", "serde", ] @@ -10945,31 +11839,14 @@ checksum = "d44f8f6dbeec3fecf9fe55f78ef0a758bdd92ea46cd4f1ca6e2a946b32c367f3" dependencies = [ "auto_impl", "derive-where", - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context 12.1.0", "revm-context-interface 13.1.0", - "revm-database-interface 8.0.5", + "revm-database-interface", "revm-interpreter 31.1.0", "revm-precompile 31.0.0", - "revm-primitives 21.0.2", - "revm-state 8.1.1", - "serde", -] - -[[package]] -name = "revm-inspector" -version = "8.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78db140e332489094ef314eaeb0bd1849d6d01172c113ab0eb6ea8ab9372926" -dependencies = [ - "auto_impl", - "either", - "revm-context 8.0.4", - "revm-database-interface 7.0.5", - "revm-handler 8.1.0", - "revm-interpreter 24.0.0", - "revm-primitives 20.2.1", - "revm-state 7.0.5", + "revm-primitives", + "revm-state", "serde", ] @@ -10982,11 +11859,11 @@ dependencies = [ "auto_impl", "either", "revm-context 11.0.2", - "revm-database-interface 8.0.5", + "revm-database-interface", "revm-handler 12.0.2", "revm-interpreter 29.0.1", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-primitives", + "revm-state", "serde", "serde_json", ] @@ -11000,11 +11877,11 @@ dependencies = [ "auto_impl", "either", "revm-context 12.1.0", - "revm-database-interface 8.0.5", + "revm-database-interface", "revm-handler 14.1.0", "revm-interpreter 31.1.0", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-primitives", + "revm-state", "serde", "serde_json", ] @@ -11027,28 +11904,16 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "revm-interpreter" -version = "24.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff9d7d9d71e8a33740b277b602165b6e3d25fff091ba3d7b5a8d373bf55f28a7" -dependencies = [ - "revm-bytecode 6.2.2", - "revm-context-interface 9.0.0", - "revm-primitives 20.2.1", - "serde", -] - [[package]] name = "revm-interpreter" version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22789ce92c5808c70185e3bc49732f987dc6fd907f77828c8d3470b2299c9c65" dependencies = [ - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context-interface 12.0.1", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-primitives", + "revm-state", "serde", ] @@ -11058,35 +11923,13 @@ version = "31.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26ec36405f7477b9dccdc6caa3be19adf5662a7a0dffa6270cdb13a090c077e5" dependencies = [ - "revm-bytecode 7.1.1", + "revm-bytecode", "revm-context-interface 13.1.0", - "revm-primitives 21.0.2", - "revm-state 8.1.1", + "revm-primitives", + "revm-state", "serde", ] -[[package]] -name = "revm-precompile" -version = "25.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cee3f336b83621294b4cfe84d817e3eef6f3d0fce00951973364cc7f860424d" -dependencies = [ - "ark-bls12-381", - "ark-bn254", - "ark-ec", - "ark-ff 0.5.0", - "ark-serialize 0.5.0", - "arrayref", - "aurora-engine-modexp", - "cfg-if", - "k256", - "once_cell", - "p256", - "revm-primitives 20.2.1", - "ripemd", - "sha2", -] - [[package]] name = "revm-precompile" version = "29.0.1" @@ -11105,7 +11948,7 @@ dependencies = [ "cfg-if", "k256", "p256", - "revm-primitives 21.0.2", + "revm-primitives", "ripemd", "rug", "secp256k1 0.31.1", @@ -11129,25 +11972,13 @@ dependencies = [ "cfg-if", "k256", "p256", - "revm-primitives 21.0.2", + "revm-primitives", "ripemd", "rug", "secp256k1 0.31.1", "sha2", ] -[[package]] -name = "revm-primitives" -version = "20.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa29d9da06fe03b249b6419b33968ecdf92ad6428e2f012dc57bcd619b5d94e" -dependencies = [ - "alloy-primitives", - "num_enum", - "once_cell", - "serde", -] - [[package]] name = "revm-primitives" version = "21.0.2" @@ -11160,18 +11991,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-state" -version = "7.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" -dependencies = [ - "bitflags 2.10.0", - "revm-bytecode 6.2.2", - "revm-primitives 20.2.1", - "serde", -] - [[package]] name = "revm-state" version = "8.1.1" @@ -11179,8 +11998,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" dependencies = [ "bitflags 2.10.0", - "revm-bytecode 7.1.1", - "revm-primitives 21.0.2", + "revm-bytecode", + "revm-primitives", "serde", ] @@ -11369,6 +12188,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rtnetlink" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" +dependencies = [ + "futures", + "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-packet-utils", + "netlink-proto", + "netlink-sys", + "nix", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "rug" version = "1.28.0" @@ -11455,6 +12292,15 @@ dependencies = [ "semver 1.0.27", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "0.38.44" @@ -11585,6 +12431,17 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + [[package]] name = "ryu" version = "1.0.22" @@ -11856,6 +12713,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -12108,6 +12974,23 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core 0.6.4", + "ring", + "rustc_version 0.4.1", + "sha2", + "subtle", +] + [[package]] name = "socket2" version = "0.5.10" @@ -12734,11 +13617,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_edit 0.22.27", ] +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -12765,7 +13661,7 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.13.0", "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_write", "winnow", @@ -13301,6 +14197,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "unsigned-varint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" + [[package]] name = "unsigned-varint" version = "0.8.0" @@ -13660,6 +14562,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" +dependencies = [ + "windows-core 0.53.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.57.0" @@ -13691,6 +14603,16 @@ dependencies = [ "windows-core 0.62.2", ] +[[package]] +name = "windows-core" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +dependencies = [ + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.57.0" @@ -14190,6 +15112,35 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.17", + "time", +] + [[package]] name = "xattr" version = "1.6.1" @@ -14200,12 +15151,67 @@ dependencies = [ "rustix 1.1.3", ] +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "yamux" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deab71f2e20691b4728b349c6cee8fc7223880fa67b6b4f92225ec32225447e5" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand 0.9.2", + "static_assertions", + "web-time", +] + [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index 1e762c8b..dd5f748e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,11 +53,11 @@ codegen-units = 1 [workspace.dependencies] # Shared -base-access-lists = { path = "crates/shared/access-lists" } base-bundles = { path = "crates/shared/bundles" } base-cli-utils = { path = "crates/shared/cli-utils" } base-flashtypes = { path = "crates/shared/flashtypes" } base-primitives = { path = "crates/shared/primitives" } +base-access-lists = { path = "crates/shared/access-lists" } base-reth-rpc-types = { path = "crates/shared/reth-rpc-types" } base-jwt = { path = "crates/shared/jwt" } # Client @@ -67,6 +67,20 @@ base-metering = { path = "crates/client/metering" } base-txpool = { path = "crates/client/txpool" } base-flashblocks = { path = "crates/client/flashblocks" } +# Kona +kona-rpc = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-disc = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-engine = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-derive = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-gossip = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-genesis = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-registry = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-node-service = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-providers-alloy = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-cli = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-peers = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } +kona-sources = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } + # reth reth-ipc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } @@ -188,21 +202,23 @@ alloy-rpc-types-beacon = { version = "1.0.41", features = ["ssz"] } # op-alloy op-alloy-flz = { version = "0.13.1", default-features = false } op-alloy-network = { version = "0.22.0", default-features = false } +op-alloy-provider = { version = "0.22.0", default-features = false } op-alloy-rpc-types = { version = "0.22.0", default-features = false } op-alloy-consensus = { version = "0.22.0", default-features = false } op-alloy-rpc-jsonrpsee = { version = "0.22.0", default-features = false } op-alloy-rpc-types-engine = { version = "0.22.0", default-features = false } -op-alloy-provider = { version = "0.22.0", default-features = false } alloy-op-evm = { version = "0.23.3", default-features = false } alloy-op-hardforks = "0.4.4" +# rollup-boost +rollup-boost = { git = "https://github.com/flashbots/rollup-boost", tag = "v0.7.11" } +# rollup-boost version that matches kona's dependency (used for consensus binary) +rollup-boost-kona = { package = "rollup-boost", git = "https://github.com/flashbots/rollup-boost.git", rev = "7fda98f" } + + # op-revm op-revm = { version = "12.0.2", default-features = false } -# kona -kona-registry = "0.4.5" -kona-engine = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" } - # tokio tokio = "1.48.0" tokio-stream = "0.1.17" @@ -212,7 +228,6 @@ tokio-tungstenite = { version = "0.28.0", features = ["native-tls"] } futures = "0.3.31" reqwest = "0.12.25" futures-util = "0.3.31" -backon = "1.5" # rpc jsonrpsee = "0.26.0" @@ -223,6 +238,11 @@ vergen = "9.0.6" vergen-git2 = "1.0.7" clap = { version = "4.5.53", features = ["derive", "env", "string"] } +# Tracing +tracing = "0.1.43" +tracing-appender = "0.2.4" +tracing-subscriber = "0.3.22" + # Metrics metrics = { version = "0.24.3", default-features = false } prometheus = { version = "0.14.0", default-features = false } @@ -233,6 +253,8 @@ metrics-exporter-prometheus = { version = "0.18.1", default-features = false } url = "2.5.7" lru = "0.16.3" rand = "0.9.2" +strum = "0.27.2" +backon = "1.6.0" uuid = "1.19.0" time = { version = "0.3.44", features = ["macros", "formatting", "parsing"] } rayon = "1.11" @@ -245,21 +267,21 @@ rstest = "0.26.1" serde = "1.0.228" rustls = "0.23.35" httpmock = "0.8.2" -tracing = "0.1.43" arc-swap = "1.7.1" once_cell = "1.21.3" itertools = "0.14.0" derive_more = "2.1.0" serde_json = "1.0.145" metrics-derive = "0.1.0" -tracing-subscriber = "0.3.22" -tracing-appender = "0.2" thiserror = "2.0" async-trait = "0.1.83" parking_lot = "0.12.3" auto_impl = "1.2.0" serde_with = "3.8.1" secp256k1 = "0.30" +libp2p = "0.56.0" +libp2p-identity = "0.2.12" +discv5 = "0.10" either = { version = "1.15.0", default-features = false } tokio-util = { version = "0.7.4", features = ["codec"] } warp = "0.3.7" diff --git a/bin/consensus/Cargo.toml b/bin/consensus/Cargo.toml index abbd4b96..952793e5 100644 --- a/bin/consensus/Cargo.toml +++ b/bin/consensus/Cargo.toml @@ -15,10 +15,26 @@ workspace = true [dependencies] # Workspace base-cli-utils.workspace = true +base-client-cli.workspace = true + +# Kona +kona-disc = { workspace = true, features = ["metrics"] } +kona-derive = { workspace = true, features = ["metrics"] } +kona-engine = { workspace = true, features = ["metrics"] } +kona-gossip = { workspace = true, features = ["metrics"] } +kona-node-service = { workspace = true, features = ["metrics"] } +kona-providers-alloy = { workspace = true, features = ["metrics"] } # CLI clap.workspace = true eyre.workspace = true +strum.workspace = true + +# Tracing +tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["fmt", "env-filter"] } + +# Metrics metrics.workspace = true [build-dependencies] diff --git a/bin/consensus/src/cli.rs b/bin/consensus/src/cli.rs index 02ed5116..37ba2dc1 100644 --- a/bin/consensus/src/cli.rs +++ b/bin/consensus/src/cli.rs @@ -1,7 +1,16 @@ //! Contains the CLI entry point for the Base consensus binary. -use base_cli_utils::GlobalArgs; +use std::{sync::Arc, time::Duration}; + +use base_cli_utils::{CliStyles, GlobalArgs, LogConfig, RuntimeManager}; +use base_client_cli::{ + BuilderClientArgs, L1ClientArgs, L1ConfigFile, L2ClientArgs, L2ConfigFile, P2PArgs, + RollupBoostFlags, RpcArgs, SequencerArgs, +}; use clap::Parser; +use kona_node_service::{EngineConfig, L1ConfigBuilder, NodeMode, RollupNodeBuilder}; +use strum::IntoEnumIterator; +use tracing::{error, info}; use crate::version; @@ -11,6 +20,7 @@ use crate::version; author, version = version::SHORT_VERSION, long_version = version::LONG_VERSION, + styles = CliStyles::init(), about, long_about = None )] @@ -18,17 +28,160 @@ pub struct Cli { /// Global arguments for the Base Consensus CLI. #[command(flatten)] pub global: GlobalArgs, + /// The mode to run the node in. + #[arg( + long = "mode", + default_value_t = NodeMode::Validator, + env = "KONA_NODE_MODE", + help = format!( + "The mode to run the node in. Supported modes are: {}", + NodeMode::iter() + .map(|mode| format!("\"{}\"", mode.to_string())) + .collect::>() + .join(", ") + ) + )] + pub node_mode: NodeMode, + + /// L1 RPC CLI arguments. + #[clap(flatten)] + pub l1_rpc_args: L1ClientArgs, + + /// L2 engine CLI arguments. + #[clap(flatten)] + pub l2_client_args: L2ClientArgs, + + /// Optional block builder client. + #[clap(flatten)] + pub builder_client_args: BuilderClientArgs, + + /// L1 configuration file. + #[clap(flatten)] + pub l1_config: L1ConfigFile, + /// L2 configuration file. + #[clap(flatten)] + pub l2_config: L2ConfigFile, + + /// P2P CLI arguments. + #[command(flatten)] + pub p2p_flags: P2PArgs, + /// RPC CLI arguments. + #[command(flatten)] + pub rpc_flags: RpcArgs, + /// SEQUENCER CLI arguments. + #[command(flatten)] + pub sequencer_flags: SequencerArgs, + /// Rollup Boost CLI arguments. + #[command(flatten)] + pub rollup_boost_flags: RollupBoostFlags, } impl Cli { - /// Parse the CLI arguments. - pub fn parse() -> Self { - ::parse() + /// Runs the CLI. + pub fn run(self) -> eyre::Result<()> { + // Initialize telemetry - allow subcommands to customize the filter. + Self::init_logs(&self.global)?; + + // Initialize unified metrics + self.global.metrics.init_with(|| { + kona_gossip::Metrics::init(); + kona_disc::Metrics::init(); + kona_engine::Metrics::init(); + kona_node_service::Metrics::init(); + kona_derive::Metrics::init(); + kona_providers_alloy::Metrics::init(); + version::VersionInfo::from_build().register_version_metrics(); + })?; + + // Run the subcommand. + RuntimeManager::run_until_ctrl_c(self.exec(&self.global)) } - /// Run the CLI. - pub fn run(self) -> eyre::Result<()> { - // TODO: Implement the CLI logic + /// Run the Node subcommand. + pub async fn exec(&self, args: &GlobalArgs) -> eyre::Result<()> { + let cfg = self.l2_config.load(&args.l2_chain_id).map_err(|e| eyre::eyre!("{e}"))?; + + info!( + target: "rollup_node", + chain_id = cfg.l2_chain_id.id(), + "Starting rollup node services" + ); + for hf in cfg.hardforks.to_string().lines() { + info!(target: "rollup_node", "{hf}"); + } + + let l1_chain_config = + self.l1_config.load(cfg.l1_chain_id).map_err(|e| eyre::eyre!("{e}"))?; + let l1_config = L1ConfigBuilder { + chain_config: l1_chain_config, + trust_rpc: self.l1_rpc_args.l1_trust_rpc, + beacon: self.l1_rpc_args.l1_beacon.clone(), + rpc_url: self.l1_rpc_args.l1_eth_rpc.clone(), + slot_duration_override: self.l1_rpc_args.l1_slot_duration_override, + }; + + // TODO: If metrics are enabled, initialize the global cli metrics. + // args.metrics.enabled.then(|| init_rollup_config_metrics(&cfg)); + + let jwt_secret = self.l2_client_args.validate_jwt().await?; + + self.p2p_flags.check_ports()?; + let genesis_signer = args.genesis_signer().ok(); + let p2p_config = self + .p2p_flags + .clone() + .config( + &cfg, + args.l2_chain_id.into(), + Some(self.l1_rpc_args.l1_eth_rpc.clone()), + genesis_signer, + ) + .await?; + let rpc_config = self.rpc_flags.clone().into(); + + let engine_config = EngineConfig { + config: Arc::new(cfg.clone()), + builder_url: self.builder_client_args.l2_builder_rpc.clone(), + builder_jwt_secret: self + .builder_client_args + .jwt_secret() + .map_err(|e| eyre::eyre!(e))?, + builder_timeout: Duration::from_millis(self.builder_client_args.builder_timeout), + l2_url: self.l2_client_args.l2_engine_rpc.clone(), + l2_jwt_secret: jwt_secret, + l2_timeout: Duration::from_millis(self.l2_client_args.l2_engine_timeout), + l1_url: self.l1_rpc_args.l1_eth_rpc.clone(), + mode: self.node_mode, + rollup_boost: self.rollup_boost_flags.clone().as_rollup_boost_args(), + }; + + RollupNodeBuilder::new( + cfg, + l1_config, + self.l2_client_args.l2_trust_rpc, + engine_config, + p2p_config, + rpc_config, + ) + .with_sequencer_config(self.sequencer_flags.config()) + .build() + .start() + .await + .map_err(|e| { + error!(target: "rollup_node", "Failed to start rollup node service: {e}"); + eyre::eyre!("{e}") + })?; + Ok(()) } + + /// Initializes the logging system based on global arguments. + pub fn init_logs(args: &GlobalArgs) -> eyre::Result<()> { + // Filter out discovery warnings since they're very very noisy. + let filter = tracing_subscriber::EnvFilter::from_default_env() + .add_directive("discv5=error".parse()?); + + let config: LogConfig = args.logging.clone().into(); + config.init_tracing_subscriber_with_filter(filter) + } } diff --git a/bin/consensus/src/main.rs b/bin/consensus/src/main.rs index ab12147b..6932760a 100644 --- a/bin/consensus/src/main.rs +++ b/bin/consensus/src/main.rs @@ -7,6 +7,8 @@ pub mod cli; pub mod version; fn main() { + use clap::Parser; + base_cli_utils::Backtracing::enable(); base_cli_utils::SigsegvHandler::install(); diff --git a/crates/client/cli/Cargo.toml b/crates/client/cli/Cargo.toml index 463d0954..d4268493 100644 --- a/crates/client/cli/Cargo.toml +++ b/crates/client/cli/Cargo.toml @@ -12,7 +12,46 @@ repository.workspace = true workspace = true [dependencies] -# General +# Shared +base-jwt = { workspace = true, features = ["engine-validation"] } + +# Kona +kona-rpc.workspace = true +kona-node-service.workspace = true +kona-engine.workspace = true +kona-genesis.workspace = true +kona-derive.workspace = true +kona-disc.workspace = true +kona-gossip.workspace = true +kona-peers.workspace = true +kona-sources.workspace = true +kona-providers-alloy.workspace = true +kona-cli = { workspace = true, features = ["secrets"] } +kona-registry.workspace = true +rollup-boost-kona.workspace = true + +# Serde +serde_json.workspace = true + +# Alloy +alloy-chains.workspace = true +alloy-primitives.workspace = true +alloy-provider.workspace = true +alloy-signer.workspace = true +alloy-signer-local.workspace = true + +# Networking +libp2p = { workspace = true, features = ["secp256k1", "macros", "tokio", "tcp", "noise", "gossipsub", "ping", "yamux", "identify"] } +discv5 = { workspace = true, features = ["libp2p"] } +reqwest.workspace = true + +# CLI url.workspace = true clap.workspace = true -alloy-rpc-types-engine.workspace = true +thiserror.workspace = true +eyre.workspace = true +tracing.workspace = true +tokio.workspace = true + +[dev-dependencies] +rstest.workspace = true diff --git a/crates/client/cli/README.md b/crates/client/cli/README.md index 6c318034..7000493c 100644 --- a/crates/client/cli/README.md +++ b/crates/client/cli/README.md @@ -8,6 +8,10 @@ This crate provides reusable CLI argument types for configuring Base node consen - **`L1ClientArgs`**: L1 execution client RPC configuration - **`L2ClientArgs`**: L2 engine API configuration with JWT handling +- **`BuilderClientArgs`**: Block builder client configuration with JWT handling +- **`RpcArgs`**: JSON-RPC server configuration +- **`SequencerArgs`**: Sequencer mode configuration +- **`RollupBoostFlags`**: Rollup boost block builder configuration ## Usage @@ -17,7 +21,7 @@ base-client-cli = { workspace = true } ``` ```rust -use base_client_cli::{L1ClientArgs, L2ClientArgs}; +use base_client_cli::{L1ClientArgs, L2ClientArgs, BuilderClientArgs}; use clap::Parser; #[derive(Parser)] @@ -26,6 +30,8 @@ struct Cli { l1_args: L1ClientArgs, #[clap(flatten)] l2_args: L2ClientArgs, + #[clap(flatten)] + builder_args: BuilderClientArgs, } ``` diff --git a/crates/client/cli/src/boost.rs b/crates/client/cli/src/boost.rs new file mode 100644 index 00000000..07cd5828 --- /dev/null +++ b/crates/client/cli/src/boost.rs @@ -0,0 +1,37 @@ +//! Rollup Boost CLI Args + +use kona_engine::RollupBoostServerArgs; +use rollup_boost_kona::ExecutionMode; + +/// Custom block builder flags. +#[derive(Clone, Debug, Default, clap::Args)] +pub struct RollupBoostFlags { + /// Whether to enable external state root computation. + #[arg( + long = "rollup-boost.external-state-root", + default_value = "false", + env = "KONA_NODE_ROLLUP_BOOST_EXTERNAL_STATE_ROOT" + )] + pub external_state_root: bool, + + /// Whether to ignore unhealthy builders. + #[arg( + long = "rollup-boost.ignore-unhealthy-builders", + default_value = "true", + env = "KONA_NODE_ROLLUP_BOOST_IGNORE_UNHEALTHY_BUILDERS" + )] + pub ignore_unhealthy_builders: bool, +} + +impl RollupBoostFlags { + /// Converts the rollup boost cli arguments to the rollup boost arguments used by the engine. + pub const fn as_rollup_boost_args(self) -> RollupBoostServerArgs { + RollupBoostServerArgs { + initial_execution_mode: ExecutionMode::DryRun, + block_selection_policy: None, + external_state_root: self.external_state_root, + ignore_unhealthy_builders: self.ignore_unhealthy_builders, + flashblocks: None, + } + } +} diff --git a/crates/client/cli/src/builder.rs b/crates/client/cli/src/builder.rs new file mode 100644 index 00000000..3c2af6f5 --- /dev/null +++ b/crates/client/cli/src/builder.rs @@ -0,0 +1,62 @@ +//! Builder Client CLI arguments with JWT handling. + +use std::path::PathBuf; + +use base_jwt::{JwtError, JwtSecret, resolve_jwt_secret}; +use url::Url; + +const DEFAULT_BUILDER_TIMEOUT: u64 = 30; + +/// Rollup-boost builder client arguments. +#[derive(Clone, Debug, clap::Args)] +pub struct BuilderClientArgs { + /// URL of the builder RPC API. + #[arg( + long, + visible_alias = "builder", + env = "KONA_NODE_BUILDER_RPC", + default_value = "http://localhost:8552" + )] + pub l2_builder_rpc: Url, + /// Hex encoded JWT secret to use for the authenticated builder RPC server. + #[arg(long, visible_alias = "builder.auth", env = "KONA_NODE_BUILDER_AUTH")] + pub builder_jwt_secret: Option, + /// Path to a JWT secret to use for the authenticated builder RPC server. + #[arg(long, visible_alias = "builder.jwt-path", env = "KONA_NODE_BUILDER_JWT_PATH")] + pub builder_jwt_path: Option, + /// Timeout for http calls in milliseconds. + #[arg( + long, + visible_alias = "builder.timeout", + env = "KONA_NODE_BUILDER_TIMEOUT", + default_value_t = DEFAULT_BUILDER_TIMEOUT + )] + pub builder_timeout: u64, +} + +impl Default for BuilderClientArgs { + fn default() -> Self { + Self { + l2_builder_rpc: Url::parse("http://localhost:8552").unwrap(), + builder_jwt_secret: None, + builder_jwt_path: None, + builder_timeout: DEFAULT_BUILDER_TIMEOUT, + } + } +} + +impl BuilderClientArgs { + /// Returns the builder JWT secret. + /// + /// Resolution order: + /// 1. Read from file path if `builder_jwt_path` is set + /// 2. Use encoded secret if `builder_jwt_secret` is set + /// 3. Fall back to default JWT file `builder_jwt.hex` + pub fn jwt_secret(&self) -> Result { + resolve_jwt_secret( + self.builder_jwt_path.as_deref(), + self.builder_jwt_secret, + "builder_jwt.hex", + ) + } +} diff --git a/crates/client/cli/src/config.rs b/crates/client/cli/src/config.rs new file mode 100644 index 00000000..733f8dd7 --- /dev/null +++ b/crates/client/cli/src/config.rs @@ -0,0 +1,145 @@ +//! Configuration file path wrappers for L1 and L2 configs. +//! +//! These types wrap `Option` and provide methods to load +//! the configuration from a file or fall back to the registry. + +use std::{fs::File, path::PathBuf}; + +use alloy_chains::Chain; +use kona_genesis::{L1ChainConfig, RollupConfig}; +use kona_registry::{L1Config, scr_rollup_config_by_alloy_ident}; +use serde_json::from_reader; +use tracing::debug; + +/// Error type for configuration loading. +#[derive(Debug, thiserror::Error)] +pub enum ConfigError { + /// Failed to open configuration file. + #[error("Failed to open config file: {0}")] + OpenFile(std::io::Error), + /// Failed to parse configuration file. + #[error("Failed to parse config: {0}")] + Parse(serde_json::Error), + /// Failed to find configuration in registry. + #[error("Failed to find config for chain ID {0}")] + NotFound(u64), +} + +/// L1 configuration file path wrapper. +/// +/// Wraps an optional path to a custom L1 chain configuration file. +/// If no path is provided, the configuration is loaded from the known chains registry. +#[derive(Clone, Debug, Default, clap::Args)] +pub struct L1ConfigFile { + /// Path to a custom L1 chain configuration file. + /// (overrides the default configuration from the registry) + #[arg(long, visible_alias = "rollup-l1-cfg", env = "KONA_NODE_L1_CHAIN_CONFIG")] + pub l1_config_file: Option, +} + +impl L1ConfigFile { + /// Creates a new [`L1ConfigFile`] with the given path. + pub const fn new(path: Option) -> Self { + Self { l1_config_file: path } + } + + /// Returns the path to the configuration file, if set. + pub const fn path(&self) -> Option<&PathBuf> { + self.l1_config_file.as_ref() + } + + /// Loads the L1 chain configuration. + /// + /// If a file path is set, loads the configuration from the JSON file. + /// Otherwise, falls back to the known chains registry using the provided chain ID. + pub fn load(&self, l1_chain_id: u64) -> Result { + match &self.l1_config_file { + Some(path) => { + debug!("Loading l1 config from file: {:?}", path); + let file = File::open(path).map_err(ConfigError::OpenFile)?; + from_reader(file).map_err(ConfigError::Parse) + } + None => { + debug!("Loading l1 config from known chains"); + let cfg = L1Config::get_l1_genesis(l1_chain_id) + .map_err(|_| ConfigError::NotFound(l1_chain_id))?; + Ok(cfg.into()) + } + } + } +} + +/// L2 rollup configuration file path wrapper. +/// +/// Wraps an optional path to a custom L2 rollup configuration file. +/// If no path is provided, the configuration is loaded from the superchain registry. +#[derive(Clone, Debug, Default, clap::Args)] +pub struct L2ConfigFile { + /// Path to a custom L2 rollup configuration file. + /// (overrides the default rollup configuration from the registry) + #[arg(long, visible_alias = "rollup-cfg", env = "KONA_NODE_ROLLUP_CONFIG")] + pub l2_config_file: Option, +} + +impl L2ConfigFile { + /// Creates a new [`L2ConfigFile`] with the given path. + pub const fn new(path: Option) -> Self { + Self { l2_config_file: path } + } + + /// Returns the path to the configuration file, if set. + pub const fn path(&self) -> Option<&PathBuf> { + self.l2_config_file.as_ref() + } + + /// Loads the L2 rollup configuration. + /// + /// If a file path is set, loads the configuration from the JSON file. + /// Otherwise, falls back to the superchain registry using the provided chain. + pub fn load(&self, l2_chain: &Chain) -> Result { + match &self.l2_config_file { + Some(path) => { + debug!("Loading l2 config from file: {:?}", path); + let file = File::open(path).map_err(ConfigError::OpenFile)?; + from_reader(file).map_err(ConfigError::Parse) + } + None => { + debug!("Loading l2 config from superchain registry"); + let cfg = scr_rollup_config_by_alloy_ident(l2_chain) + .ok_or_else(|| ConfigError::NotFound(l2_chain.id()))?; + Ok(cfg.clone()) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_l1_config_file_default() { + let config = L1ConfigFile::default(); + assert!(config.path().is_none()); + } + + #[test] + fn test_l2_config_file_default() { + let config = L2ConfigFile::default(); + assert!(config.path().is_none()); + } + + #[test] + fn test_l1_config_file_with_path() { + let path = PathBuf::from("/tmp/l1_config.json"); + let config = L1ConfigFile::new(Some(path.clone())); + assert_eq!(config.path(), Some(&path)); + } + + #[test] + fn test_l2_config_file_with_path() { + let path = PathBuf::from("/tmp/l2_config.json"); + let config = L2ConfigFile::new(Some(path.clone())); + assert_eq!(config.path(), Some(&path)); + } +} diff --git a/crates/client/cli/src/l2.rs b/crates/client/cli/src/l2.rs index ed0198d8..201e374b 100644 --- a/crates/client/cli/src/l2.rs +++ b/crates/client/cli/src/l2.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; -use alloy_rpc_types_engine::JwtSecret; +use base_jwt::{JwtError, JwtSecret, JwtValidator, resolve_jwt_secret}; use url::Url; const DEFAULT_L2_ENGINE_TIMEOUT: u64 = 30_000; @@ -51,3 +51,28 @@ impl Default for L2ClientArgs { } } } + +impl L2ClientArgs { + /// Returns the L2 JWT secret for the engine API. + /// + /// Resolution order: + /// 1. Read from file path if `l2_engine_jwt_secret` is set + /// 2. Use encoded secret if `l2_engine_jwt_encoded` is set + /// 3. Fall back to default JWT file `l2_jwt.hex` + pub fn jwt_secret(&self) -> Result { + resolve_jwt_secret( + self.l2_engine_jwt_secret.as_deref(), + self.l2_engine_jwt_encoded, + "l2_jwt.hex", + ) + } + + /// Validate the jwt secret if specified by exchanging capabilities with the engine. + /// Since the engine client will fail if the jwt token is invalid, this allows to ensure + /// that the jwt token passed as a cli arg is correct. + pub async fn validate_jwt(&self) -> eyre::Result { + let jwt_secret = self.jwt_secret().map_err(|e| eyre::eyre!(e))?; + let validator = JwtValidator::new(jwt_secret); + validator.validate_with_engine(self.l2_engine_rpc.clone()).await.map_err(|e| eyre::eyre!(e)) + } +} diff --git a/crates/client/cli/src/lib.rs b/crates/client/cli/src/lib.rs index ad91a070..652c9724 100644 --- a/crates/client/cli/src/lib.rs +++ b/crates/client/cli/src/lib.rs @@ -3,8 +3,30 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] +mod config; +pub use config::{ConfigError, L1ConfigFile, L2ConfigFile}; + mod l1; pub use l1::L1ClientArgs; mod l2; pub use l2::L2ClientArgs; + +mod builder; +pub use builder::BuilderClientArgs; + +mod rpc; +pub use rpc::RpcArgs; + +mod sequencer; +pub use sequencer::SequencerArgs; + +mod boost; +pub use base_jwt::{JwtError, JwtSecret, default_jwt_secret}; +pub use boost::RollupBoostFlags; + +pub mod signer; +pub use signer::{SignerArgs, SignerArgsParseError}; + +pub mod p2p; +pub use p2p::{P2PArgs, P2PConfigError}; diff --git a/crates/client/cli/src/p2p.rs b/crates/client/cli/src/p2p.rs new file mode 100644 index 00000000..a3011460 --- /dev/null +++ b/crates/client/cli/src/p2p.rs @@ -0,0 +1,754 @@ +//! P2P CLI Flags +//! +//! These are based on p2p flags from the [`op-node`][op-node] CLI. +//! +//! [op-node]: https://github.com/ethereum-optimism/optimism/blob/develop/op-node/flags/p2p_flags.go + +use std::{ + net::{IpAddr, SocketAddr, ToSocketAddrs}, + num::ParseIntError, + path::PathBuf, + str::FromStr, +}; + +use alloy_primitives::{B256, b256}; +use alloy_provider::Provider; +use alloy_signer_local::PrivateKeySigner; +use clap::Parser; +use discv5::enr::k256; +use eyre::Result; +use kona_derive::ChainProvider; +use kona_disc::LocalNode; +use kona_genesis::RollupConfig; +use kona_gossip::GaterConfig; +use kona_node_service::NetworkConfig; +use kona_peers::{BootNode, BootStoreFile, PeerMonitoring, PeerScoreLevel}; +use kona_providers_alloy::AlloyChainProvider; +use libp2p::identity::Keypair; +use tokio::time::Duration; +use url::Url; + +use crate::signer::{SignerArgs, SignerArgsParseError}; + +/// Resolves a hostname or IP address string to an [`IpAddr`]. +/// +/// Accepts either: +/// - A valid IP address string (e.g., "127.0.0.1", "::1") +/// - A DNS hostname (e.g., "node1.example.com") +/// +/// For DNS hostnames, this performs synchronous DNS resolution and returns the first +/// resolved IP address. +fn resolve_host(host: &str) -> Result { + // First, try to parse as a direct IP address + if let Ok(ip) = host.parse::() { + return Ok(ip); + } + + // If that fails, try DNS resolution + // We append a port to make it a valid socket address for resolution + let socket_addr = format!("{host}:0"); + match socket_addr.to_socket_addrs() { + Ok(mut addrs) => addrs + .next() + .map(|addr| addr.ip()) + .ok_or_else(|| format!("DNS resolution for '{host}' returned no addresses")), + Err(e) => Err(format!("Failed to resolve '{host}': {e}")), + } +} + +/// P2P CLI Flags +#[derive(Parser, Clone, Debug, PartialEq, Eq)] +pub struct P2PArgs { + /// Disable Discv5 (node discovery). + #[arg(long = "p2p.no-discovery", default_value = "false", env = "KONA_NODE_P2P_NO_DISCOVERY")] + pub no_discovery: bool, + /// Read the hex-encoded 32-byte private key for the peer ID from this txt file. + /// Created if not already exists. Important to persist to keep the same network identity after + /// restarting, maintaining the previous advertised identity. + #[arg(long = "p2p.priv.path", env = "KONA_NODE_P2P_PRIV_PATH")] + pub priv_path: Option, + /// The hex-encoded 32-byte private key for the peer ID. + #[arg(long = "p2p.priv.raw", env = "KONA_NODE_P2P_PRIV_RAW")] + pub private_key: Option, + + /// IP address or DNS hostname to advertise to external peers from Discv5. + /// Optional argument. Use the `p2p.listen.ip` if not set. + /// Accepts either an IP address (e.g., "1.2.3.4") or a DNS hostname (e.g., + /// "node1.example.com"). DNS hostnames are resolved to IP addresses at startup. + /// + /// Technical note: if this argument is set, the dynamic ENR updates from the discovery layer + /// will be disabled. This is to allow the advertised IP to be static (to use in a network + /// behind a NAT for instance). + #[arg(long = "p2p.advertise.ip", env = "KONA_NODE_P2P_ADVERTISE_IP", value_parser = resolve_host)] + pub advertise_ip: Option, + /// TCP port to advertise to external peers from the discovery layer. Same as `p2p.listen.tcp` + /// if set to zero. + #[arg(long = "p2p.advertise.tcp", env = "KONA_NODE_P2P_ADVERTISE_TCP_PORT")] + pub advertise_tcp_port: Option, + /// UDP port to advertise to external peers from the discovery layer. + /// Same as `p2p.listen.udp` if set to zero. + #[arg(long = "p2p.advertise.udp", env = "KONA_NODE_P2P_ADVERTISE_UDP_PORT")] + pub advertise_udp_port: Option, + + /// IP address or DNS hostname to bind LibP2P/Discv5 to. + /// Accepts either an IP address (e.g., "0.0.0.0") or a DNS hostname (e.g., + /// "node1.example.com"). DNS hostnames are resolved to IP addresses at startup. + #[arg(long = "p2p.listen.ip", default_value = "0.0.0.0", env = "KONA_NODE_P2P_LISTEN_IP", value_parser = resolve_host)] + pub listen_ip: IpAddr, + /// TCP port to bind LibP2P to. Any available system port if set to 0. + #[arg(long = "p2p.listen.tcp", default_value = "9222", env = "KONA_NODE_P2P_LISTEN_TCP_PORT")] + pub listen_tcp_port: u16, + /// UDP port to bind Discv5 to. Same as TCP port if left 0. + #[arg(long = "p2p.listen.udp", default_value = "9223", env = "KONA_NODE_P2P_LISTEN_UDP_PORT")] + pub listen_udp_port: u16, + /// Low-tide peer count. The node actively searches for new peer connections if below this + /// amount. + #[arg(long = "p2p.peers.lo", default_value = "20", env = "KONA_NODE_P2P_PEERS_LO")] + pub peers_lo: u32, + /// High-tide peer count. The node starts pruning peer connections slowly after reaching this + /// number. + #[arg(long = "p2p.peers.hi", default_value = "30", env = "KONA_NODE_P2P_PEERS_HI")] + pub peers_hi: u32, + /// Grace period to keep a newly connected peer around, if it is not misbehaving. + #[arg( + long = "p2p.peers.grace", + default_value = "30", + env = "KONA_NODE_P2P_PEERS_GRACE", + value_parser = |arg: &str| -> Result {Ok(Duration::from_secs(arg.parse()?))} + )] + pub peers_grace: Duration, + /// Configure GossipSub topic stable mesh target count. + /// Aka: The desired outbound degree (numbers of peers to gossip to). + #[arg(long = "p2p.gossip.mesh.d", default_value = "8", env = "KONA_NODE_P2P_GOSSIP_MESH_D")] + pub gossip_mesh_d: usize, + /// Configure GossipSub topic stable mesh low watermark. + /// Aka: The lower bound of outbound degree. + #[arg(long = "p2p.gossip.mesh.lo", default_value = "6", env = "KONA_NODE_P2P_GOSSIP_MESH_DLO")] + pub gossip_mesh_dlo: usize, + /// Configure GossipSub topic stable mesh high watermark. + /// Aka: The upper bound of outbound degree (additional peers will not receive gossip). + #[arg( + long = "p2p.gossip.mesh.dhi", + default_value = "12", + env = "KONA_NODE_P2P_GOSSIP_MESH_DHI" + )] + pub gossip_mesh_dhi: usize, + /// Configure GossipSub gossip target. + /// Aka: The target degree for gossip only (not messaging like p2p.gossip.mesh.d, just + /// announcements of IHAVE). + #[arg( + long = "p2p.gossip.mesh.dlazy", + default_value = "6", + env = "KONA_NODE_P2P_GOSSIP_MESH_DLAZY" + )] + pub gossip_mesh_dlazy: usize, + /// Configure GossipSub to publish messages to all known peers on the topic, outside of the + /// mesh. Also see Dlazy as less aggressive alternative. + #[arg( + long = "p2p.gossip.mesh.floodpublish", + default_value = "false", + env = "KONA_NODE_P2P_GOSSIP_FLOOD_PUBLISH" + )] + pub gossip_flood_publish: bool, + /// Sets the peer scoring strategy for the P2P stack. + /// Can be one of: none or light. + #[arg(long = "p2p.scoring", default_value = "light", env = "KONA_NODE_P2P_SCORING")] + pub scoring: PeerScoreLevel, + + /// Allows to ban peers based on their score. + /// + /// Peers are banned based on a ban threshold (see `p2p.ban.threshold`). + /// If a peer's score is below the threshold, it gets automatically banned. + #[arg(long = "p2p.ban.peers", default_value = "false", env = "KONA_NODE_P2P_BAN_PEERS")] + pub ban_enabled: bool, + + /// The threshold used to ban peers. + /// + /// For peers to be banned, the `p2p.ban.peers` flag must be set to `true`. + /// By default, peers are banned if their score is below -100. This follows the `op-node` default ``. + #[arg(long = "p2p.ban.threshold", default_value = "-100", env = "KONA_NODE_P2P_BAN_THRESHOLD")] + pub ban_threshold: i64, + + /// The duration in minutes to ban a peer for. + /// + /// For peers to be banned, the `p2p.ban.peers` flag must be set to `true`. + /// By default peers are banned for 1 hour. This follows the `op-node` default ``. + #[arg(long = "p2p.ban.duration", default_value = "60", env = "KONA_NODE_P2P_BAN_DURATION")] + pub ban_duration: u64, + + /// The interval in seconds to find peers using the discovery service. + /// Defaults to 5 seconds. + #[arg( + long = "p2p.discovery.interval", + default_value = "5", + env = "KONA_NODE_P2P_DISCOVERY_INTERVAL" + )] + pub discovery_interval: u64, + /// The directory to store the bootstore. + #[arg(long = "p2p.bootstore", env = "KONA_NODE_P2P_BOOTSTORE")] + pub bootstore: Option, + /// Disables the bootstore. + #[arg(long = "p2p.no-bootstore", env = "KONA_NODE_P2P_NO_BOOTSTORE")] + pub disable_bootstore: bool, + /// Peer Redialing threshold is the maximum amount of times to attempt to redial a peer that + /// disconnects. By default, peers are *not* redialed. If set to 0, the peer will be + /// redialed indefinitely. + #[arg(long = "p2p.redial", env = "KONA_NODE_P2P_REDIAL", default_value = "500")] + pub peer_redial: Option, + + /// The duration in minutes of the peer dial period. + /// When the last time a peer was dialed is longer than the dial period, the number of peer + /// dials is reset to 0, allowing the peer to be dialed again. + #[arg(long = "p2p.redial.period", env = "KONA_NODE_P2P_REDIAL_PERIOD", default_value = "60")] + pub redial_period: u64, + + /// An optional list of bootnode ENRs or node records to start the node with. + #[arg(long = "p2p.bootnodes", value_delimiter = ',', env = "KONA_NODE_P2P_BOOTNODES")] + pub bootnodes: Vec, + + /// Optionally enable topic scoring. + /// + /// Topic scoring is a mechanism to score peers based on their behavior in the gossip network. + /// Historically, topic scoring was only enabled for the v1 topic on the OP Stack p2p network + /// in the `op-node`. This was a silent bug, and topic scoring is actively being + /// [phased out of the `op-node`][out]. + /// + /// This flag is only presented for backwards compatibility and debugging purposes. + /// + /// [out]: https://github.com/ethereum-optimism/optimism/pull/15719 + #[arg( + long = "p2p.topic-scoring", + default_value = "false", + env = "KONA_NODE_P2P_TOPIC_SCORING" + )] + pub topic_scoring: bool, + + /// An optional unsafe block signer address. + /// + /// By default, this is fetched from the chain config in the superchain-registry using the + /// specified L2 chain ID. + #[arg(long = "p2p.unsafe.block.signer", env = "KONA_NODE_P2P_UNSAFE_BLOCK_SIGNER")] + pub unsafe_block_signer: Option, + + /// An optional flag to remove random peers from discovery to rotate the peer set. + /// + /// This is the number of seconds to wait before removing a peer from the discovery + /// service. By default, peers are not removed from the discovery service. + /// + /// This is useful for discovering a wider set of peers. + #[arg(long = "p2p.discovery.randomize", env = "KONA_NODE_P2P_DISCOVERY_RANDOMIZE")] + pub discovery_randomize: Option, + + /// Specify optional remote signer configuration. Note that this argument is mutually exclusive + /// with `p2p.sequencer.key` that specifies a local sequencer signer. + #[command(flatten)] + pub signer: SignerArgs, +} + +impl Default for P2PArgs { + fn default() -> Self { + // Construct default values using the clap parser. + // This works since none of the cli flags are required. + Self::parse_from::<[_; 0], &str>([]) + } +} + +/// Errors that can occur when building a P2P network configuration. +#[derive(Debug, thiserror::Error)] +pub enum P2PConfigError { + /// Error from signer args parsing. + #[error(transparent)] + SignerArgs(#[from] SignerArgsParseError), + /// Error from eyre. + #[error(transparent)] + Eyre(#[from] eyre::Error), +} + +impl P2PArgs { + fn check_ports_inner(ip_addr: IpAddr, tcp_port: u16, udp_port: u16) -> Result<()> { + if tcp_port == 0 { + return Ok(()); + } + if udp_port == 0 { + return Ok(()); + } + let tcp_socket = std::net::TcpListener::bind((ip_addr, tcp_port)); + let udp_socket = std::net::UdpSocket::bind((ip_addr, udp_port)); + if let Err(e) = tcp_socket { + tracing::error!(target: "p2p::flags", tcp_port, "Error binding TCP socket: {e}"); + eyre::bail!("Error binding TCP socket on port {tcp_port}: {e}"); + } + if let Err(e) = udp_socket { + tracing::error!(target: "p2p::flags", udp_port, "Error binding UDP socket: {e}"); + eyre::bail!("Error binding UDP socket on port {udp_port}: {e}"); + } + + Ok(()) + } + + /// Checks if the listen ports are available on the system. + /// + /// If either of the ports are `0`, this check is skipped. + /// + /// ## Errors + /// + /// - If the TCP port is already in use. + /// - If the UDP port is already in use. + pub fn check_ports(&self) -> Result<()> { + Self::check_ports_inner(self.listen_ip, self.listen_tcp_port, self.listen_udp_port) + } + + /// Returns the private key as specified in the raw cli flag or via file path. + pub fn private_key(&self) -> Option { + if let Some(key) = self.private_key { + match PrivateKeySigner::from_bytes(&key) { + Ok(signer) => return Some(signer), + Err(e) => { + tracing::error!(target: "p2p::flags", "Failed to parse private key: {}", e); + return None; + } + } + } + + if let Some(path) = self.priv_path.as_ref() + && path.exists() + { + let contents = std::fs::read_to_string(path).ok()?; + let decoded = B256::from_str(&contents).ok()?; + match PrivateKeySigner::from_bytes(&decoded) { + Ok(signer) => return Some(signer), + Err(e) => { + tracing::error!(target: "p2p::flags", "Failed to parse private key from file: {}", e); + return None; + } + } + } + + None + } + + /// Returns the unsafe block signer from the CLI arguments. + /// + /// This method fetches the unsafe block signer from L1 if an RPC URL is provided, + /// otherwise falls back to the genesis signer or the configured unsafe block signer. + pub async fn unsafe_block_signer( + &self, + l2_chain_id: u64, + rollup_config: &RollupConfig, + l1_eth_rpc: Option, + genesis_signer: Option, + ) -> eyre::Result { + if let Some(l1_eth_rpc) = l1_eth_rpc { + /// The storage slot that the unsafe block signer address is stored at. + /// Computed as: `bytes32(uint256(keccak256("systemconfig.unsafeblocksigner")) - 1)` + const UNSAFE_BLOCK_SIGNER_ADDRESS_STORAGE_SLOT: B256 = + b256!("0x65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08"); + + let mut provider = AlloyChainProvider::new_http(l1_eth_rpc, 1024); + let latest_block_num = provider.latest_block_number().await?; + let block_info = provider.block_info_by_number(latest_block_num).await?; + + // Fetch the unsafe block signer address from the system config. + let unsafe_block_signer_address = provider + .inner + .get_storage_at( + rollup_config.l1_system_config_address, + UNSAFE_BLOCK_SIGNER_ADDRESS_STORAGE_SLOT.into(), + ) + .hash(block_info.hash) + .await?; + + // Convert the unsafe block signer address to the correct type. + return Ok(alloy_primitives::Address::from_slice( + &unsafe_block_signer_address.to_be_bytes_vec()[12..], + )); + } + + // Otherwise use the genesis signer or the configured unsafe block signer. + genesis_signer.or(self.unsafe_block_signer).ok_or_else(|| { + eyre::eyre!( + "Unsafe block signer not provided for chain ID {}. \ + Provide --p2p.unsafe.block.signer or ensure the chain is in the superchain registry.", + l2_chain_id + ) + }) + } + + /// Constructs kona's P2P network [`NetworkConfig`] from CLI arguments. + /// + /// ## Parameters + /// + /// - `config`: The rollup configuration. + /// - `l2_chain_id`: The L2 chain ID. + /// - `l1_rpc`: Optional L1 RPC URL for fetching the unsafe block signer. + /// - `genesis_signer`: Optional genesis signer address. + /// + /// Errors if the genesis unsafe block signer isn't available for the specified L2 Chain ID. + pub async fn config( + self, + config: &RollupConfig, + l2_chain_id: u64, + l1_rpc: Option, + genesis_signer: Option, + ) -> Result { + // Note: the advertised address is contained in the ENR for external peers from the + // discovery layer to use. + + // Fallback to the listen ip if the advertise ip is not specified + let advertise_ip = self.advertise_ip.unwrap_or(self.listen_ip); + + // If the advertise ip is set, we will disable the dynamic ENR updates. + let static_ip = self.advertise_ip.is_some(); + + // If the advertise tcp port is null, use the listen tcp port + let advertise_tcp_port = match self.advertise_tcp_port { + None => self.listen_tcp_port, + Some(port) => port, + }; + + let advertise_udp_port = match self.advertise_udp_port { + None => self.listen_udp_port, + Some(port) => port, + }; + + let keypair = self.keypair().unwrap_or_else(|e| { + let generated = Keypair::generate_secp256k1(); + tracing::warn!( + target: "p2p::config", + error = %e, + peer_id = %generated.public().to_peer_id(), + "Failed to load P2P keypair from configuration, generated ephemeral keypair. \ + Set --p2p.priv.path or --p2p.priv.raw for a persistent peer ID." + ); + generated + }); + let secp256k1_key = keypair.clone().try_into_secp256k1() + .map_err(|e| eyre::eyre!("Impossible to convert keypair to secp256k1. This is a bug since we only support secp256k1 keys: {e}"))? + .secret().to_bytes(); + let local_node_key = k256::ecdsa::SigningKey::from_bytes(&secp256k1_key.into()) + .map_err(|e| eyre::eyre!("Impossible to convert keypair to k256 signing key. This is a bug since we only support secp256k1 keys: {e}"))?; + + let discovery_address = + LocalNode::new(local_node_key, advertise_ip, advertise_tcp_port, advertise_udp_port); + let gossip_config = kona_gossip::default_config_builder() + .mesh_n(self.gossip_mesh_d) + .mesh_n_low(self.gossip_mesh_dlo) + .mesh_n_high(self.gossip_mesh_dhi) + .gossip_lazy(self.gossip_mesh_dlazy) + .flood_publish(self.gossip_flood_publish) + .build() + .map_err(|e| eyre::eyre!("Failed to build gossip config: {e}"))?; + + let monitor_peers = self.ban_enabled.then_some(PeerMonitoring { + ban_duration: Duration::from_secs(60 * self.ban_duration), + ban_threshold: self.ban_threshold as f64, + }); + + let discovery_listening_address = SocketAddr::new(self.listen_ip, self.listen_udp_port); + let discovery_config = + NetworkConfig::discv5_config(discovery_listening_address.into(), static_ip); + + let mut gossip_address = libp2p::Multiaddr::from(self.listen_ip); + gossip_address.push(libp2p::multiaddr::Protocol::Tcp(self.listen_tcp_port)); + + let unsafe_block_signer = + self.unsafe_block_signer(l2_chain_id, config, l1_rpc, genesis_signer).await?; + + let bootstore = + if self.disable_bootstore { + None + } else { + Some(self.bootstore.map_or( + BootStoreFile::Default { chain_id: l2_chain_id }, + BootStoreFile::Custom, + )) + }; + + let bootnodes = self + .bootnodes + .iter() + .map(|bootnode| BootNode::parse_bootnode(bootnode)) + .collect::>() + .into(); + + Ok(NetworkConfig { + discovery_config, + discovery_interval: Duration::from_secs(self.discovery_interval), + discovery_address, + discovery_randomize: self.discovery_randomize.map(Duration::from_secs), + enr_update: !static_ip, + gossip_address, + keypair, + unsafe_block_signer, + gossip_config, + scoring: self.scoring, + monitor_peers, + bootstore, + topic_scoring: self.topic_scoring, + gater_config: GaterConfig { + peer_redialing: self.peer_redial, + dial_period: Duration::from_secs(60 * self.redial_period), + }, + bootnodes, + rollup_config: config.clone(), + gossip_signer: self.signer.config(l2_chain_id)?, + }) + } + + /// Returns the [`Keypair`] from the cli inputs. + /// + /// If the raw private key is empty and the specified file is empty, + /// this method will generate a new private key and write it out to the file. + /// + /// If neither a file is specified, nor a raw private key input, this method + /// will error. + pub fn keypair(&self) -> Result { + // Attempt the parse the private key if specified. + if let Some(mut private_key) = self.private_key { + let keypair = + kona_cli::SecretKeyLoader::parse(&mut private_key.0).map_err(|e| eyre::eyre!(e))?; + tracing::info!( + target: "p2p::config", + peer_id = %keypair.public().to_peer_id(), + "Successfully loaded P2P keypair from raw private key" + ); + return Ok(keypair); + } + + let Some(ref key_path) = self.priv_path else { + eyre::bail!("Neither a raw private key nor a private key file path was provided."); + }; + + kona_cli::SecretKeyLoader::load(key_path).map_err(|e| eyre::eyre!(e)) + } +} + +#[cfg(test)] +mod tests { + use alloy_primitives::b256; + use clap::Parser; + use kona_peers::NodeRecord; + + use super::*; + + /// A mock command that uses the P2PArgs. + #[derive(Parser, Debug, Clone)] + #[command(about = "Mock command")] + struct MockCommand { + /// P2P CLI Flags + #[clap(flatten)] + pub p2p: P2PArgs, + } + + #[test] + fn test_p2p_args_keypair_missing_both() { + let args = MockCommand::parse_from(["test"]); + assert!(args.p2p.keypair().is_err()); + } + + #[test] + fn test_p2p_args_keypair_raw_private_key() { + let args = MockCommand::parse_from([ + "test", + "--p2p.priv.raw", + "1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be", + ]); + assert!(args.p2p.keypair().is_ok()); + } + + #[test] + fn test_p2p_args_keypair_from_path() { + // Create a temporary directory. + let dir = std::env::temp_dir(); + let mut source_path = dir.clone(); + assert!(std::env::set_current_dir(dir).is_ok()); + + // Write a private key to a file. + let key = b256!("1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be"); + let hex = alloy_primitives::hex::encode(key.0); + source_path.push("test.txt"); + std::fs::write(&source_path, &hex).unwrap(); + + // Parse the keypair from the file. + let args = + MockCommand::parse_from(["test", "--p2p.priv.path", source_path.to_str().unwrap()]); + assert!(args.p2p.keypair().is_ok()); + } + + #[test] + fn test_p2p_args() { + let args = MockCommand::parse_from(["test"]); + assert_eq!(args.p2p, P2PArgs::default()); + } + + #[test] + fn test_p2p_args_randomized() { + let args = MockCommand::parse_from(["test", "--p2p.discovery.randomize", "10"]); + assert_eq!(args.p2p.discovery_randomize, Some(10)); + let args = MockCommand::parse_from(["test"]); + assert_eq!(args.p2p.discovery_randomize, None); + } + + #[test] + fn test_p2p_args_no_discovery() { + let args = MockCommand::parse_from(["test", "--p2p.no-discovery"]); + assert!(args.p2p.no_discovery); + } + + #[test] + fn test_p2p_args_priv_path() { + let args = MockCommand::parse_from(["test", "--p2p.priv.path", "test.txt"]); + assert_eq!(args.p2p.priv_path, Some(PathBuf::from("test.txt"))); + } + + #[test] + fn test_p2p_args_private_key() { + let args = MockCommand::parse_from([ + "test", + "--p2p.priv.raw", + "1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be", + ]); + let key = b256!("1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be"); + assert_eq!(args.p2p.private_key, Some(key)); + } + + #[test] + fn test_p2p_args_sequencer_key() { + let args = MockCommand::parse_from([ + "test", + "--p2p.sequencer.key", + "bcc617ea05150ff60490d3c6058630ba94ae9f12a02a87efd291349ca0e54e0a", + ]); + let key = b256!("bcc617ea05150ff60490d3c6058630ba94ae9f12a02a87efd291349ca0e54e0a"); + assert_eq!(args.p2p.signer.sequencer_key, Some(key)); + } + + #[test] + fn test_p2p_args_listen_ip() { + let args = MockCommand::parse_from(["test", "--p2p.listen.ip", "127.0.0.1"]); + let expected: IpAddr = "127.0.0.1".parse().unwrap(); + assert_eq!(args.p2p.listen_ip, expected); + } + + #[test] + fn test_p2p_args_listen_tcp_port() { + let args = MockCommand::parse_from(["test", "--p2p.listen.tcp", "1234"]); + assert_eq!(args.p2p.listen_tcp_port, 1234); + } + + #[test] + fn test_p2p_args_listen_udp_port() { + let args = MockCommand::parse_from(["test", "--p2p.listen.udp", "1234"]); + assert_eq!(args.p2p.listen_udp_port, 1234); + } + + #[test] + fn test_p2p_args_bootnodes() { + let args = MockCommand::parse_from([ + "test", + "--p2p.bootnodes", + "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305", + ]); + assert_eq!( + args.p2p.bootnodes, + vec![ + "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305", + ] + ); + + // Parse the bootnodes. + let bootnodes = args + .p2p + .bootnodes + .iter() + .map(|bootnode| BootNode::parse_bootnode(bootnode)) + .collect::>(); + + // Otherwise, attempt to use the Node Record format. + let record = NodeRecord::from_str( + "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305").unwrap(); + let expected_bootnode = vec![BootNode::from_unsigned(record).unwrap()]; + + assert_eq!(bootnodes, expected_bootnode); + } + + #[test] + fn test_p2p_args_bootnodes_multiple() { + let args = MockCommand::parse_from([ + "test", + "--p2p.bootnodes", + "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305,enode://dd751a9ef8912be1bfa7a5e34e2c3785cc5253110bd929f385e07ba7ac19929fb0e0c5d93f77827291f4da02b2232240fbc47ea7ce04c46e333e452f8656b667@34.65.107.0:30305", + ]); + assert_eq!( + args.p2p.bootnodes, + vec![ + "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305", + "enode://dd751a9ef8912be1bfa7a5e34e2c3785cc5253110bd929f385e07ba7ac19929fb0e0c5d93f77827291f4da02b2232240fbc47ea7ce04c46e333e452f8656b667@34.65.107.0:30305", + ] + ); + } + + #[test] + fn test_p2p_args_bootnode_enr() { + let args = MockCommand::parse_from([ + "test", + "--p2p.bootnodes", + "enr:-J64QBbwPjPLZ6IOOToOLsSjtFUjjzN66qmBZdUexpO32Klrc458Q24kbty2PdRaLacHM5z-cZQr8mjeQu3pik6jPSOGAYYFIqBfgmlkgnY0gmlwhDaRWFWHb3BzdGFja4SzlAUAiXNlY3AyNTZrMaECmeSnJh7zjKrDSPoNMGXoopeDF4hhpj5I0OsQUUt4u8uDdGNwgiQGg3VkcIIkBg", + ]); + assert_eq!( + args.p2p.bootnodes, + vec![ + "enr:-J64QBbwPjPLZ6IOOToOLsSjtFUjjzN66qmBZdUexpO32Klrc458Q24kbty2PdRaLacHM5z-cZQr8mjeQu3pik6jPSOGAYYFIqBfgmlkgnY0gmlwhDaRWFWHb3BzdGFja4SzlAUAiXNlY3AyNTZrMaECmeSnJh7zjKrDSPoNMGXoopeDF4hhpj5I0OsQUUt4u8uDdGNwgiQGg3VkcIIkBg", + ] + ); + } + + #[test] + fn test_p2p_args_listen_ip_dns_resolution() { + // Test that DNS hostnames are resolved to IP addresses + // Using localhost which should resolve reliably + let args = MockCommand::parse_from(["test", "--p2p.listen.ip", "localhost"]); + // localhost typically resolves to 127.0.0.1 or ::1 + assert!( + args.p2p.listen_ip == "127.0.0.1".parse::().unwrap() + || args.p2p.listen_ip == "::1".parse::().unwrap() + ); + } + + #[test] + fn test_p2p_args_advertise_ip_dns_resolution() { + // Test that DNS hostnames are resolved to IP addresses for advertise_ip + let args = MockCommand::parse_from(["test", "--p2p.advertise.ip", "localhost"]); + // localhost typically resolves to 127.0.0.1 or ::1 + let ip = args.p2p.advertise_ip.unwrap(); + assert!( + ip == "127.0.0.1".parse::().unwrap() || ip == "::1".parse::().unwrap() + ); + } + + #[test] + fn test_resolve_host_with_ip() { + // Test that IP addresses are passed through directly + let ip = resolve_host("192.168.1.1").unwrap(); + assert_eq!(ip, "192.168.1.1".parse::().unwrap()); + + let ipv6 = resolve_host("::1").unwrap(); + assert_eq!(ipv6, "::1".parse::().unwrap()); + } + + #[test] + fn test_resolve_host_with_dns() { + // Test DNS resolution with localhost + let ip = resolve_host("localhost").unwrap(); + assert!( + ip == "127.0.0.1".parse::().unwrap() || ip == "::1".parse::().unwrap() + ); + } + + #[test] + fn test_resolve_host_invalid() { + // Test that invalid hostnames return an error + let result = resolve_host("this-hostname-definitely-does-not-exist.invalid"); + assert!(result.is_err()); + } +} diff --git a/crates/client/cli/src/rpc.rs b/crates/client/cli/src/rpc.rs new file mode 100644 index 00000000..957cdf27 --- /dev/null +++ b/crates/client/cli/src/rpc.rs @@ -0,0 +1,90 @@ +//! Rpc CLI Arguments +//! +//! Flags for configuring the RPC server. + +use std::{ + net::{IpAddr, SocketAddr}, + path::PathBuf, +}; + +use clap::Parser; +use kona_rpc::RpcBuilder; + +/// RPC CLI Arguments +#[derive(Parser, Debug, Clone, PartialEq, Eq)] +pub struct RpcArgs { + /// Whether to disable the rpc server. + #[arg(long = "rpc.disabled", default_value = "false", env = "KONA_NODE_RPC_DISABLED")] + pub rpc_disabled: bool, + /// Prevent the RPC server from attempting to restart. + #[arg(long = "rpc.no-restart", default_value = "false", env = "KONA_NODE_RPC_NO_RESTART")] + pub no_restart: bool, + /// RPC listening address. + #[arg(long = "rpc.addr", default_value = "0.0.0.0", env = "KONA_NODE_RPC_ADDR")] + pub listen_addr: IpAddr, + /// RPC listening port. + #[arg(long = "port", alias = "rpc.port", default_value = "9545", env = "KONA_NODE_RPC_PORT")] + pub listen_port: u16, + /// Enable the admin API. + #[arg(long = "rpc.enable-admin", env = "KONA_NODE_RPC_ENABLE_ADMIN")] + pub enable_admin: bool, + /// File path used to persist state changes made via the admin API so they persist across + /// restarts. Disabled if not set. + #[arg(long = "rpc.admin-state", env = "KONA_NODE_RPC_ADMIN_STATE")] + pub admin_persistence: Option, + /// Enables websocket rpc server to track block production + #[arg(long = "rpc.ws-enabled", default_value = "false", env = "KONA_NODE_RPC_WS_ENABLED")] + pub ws_enabled: bool, + /// Enables development RPC endpoints for engine state introspection + #[arg(long = "rpc.dev-enabled", default_value = "false", env = "KONA_NODE_RPC_DEV_ENABLED")] + pub dev_enabled: bool, +} + +impl Default for RpcArgs { + fn default() -> Self { + // Construct default values using the clap parser. + // This works since none of the cli flags are required. + Self::parse_from::<[_; 0], &str>([]) + } +} + +impl From for Option { + fn from(args: RpcArgs) -> Self { + if args.rpc_disabled { + return None; + } + Some(RpcBuilder { + no_restart: args.no_restart, + socket: SocketAddr::new(args.listen_addr, args.listen_port), + enable_admin: args.enable_admin, + admin_persistence: args.admin_persistence, + ws_enabled: args.ws_enabled, + dev_enabled: args.dev_enabled, + }) + } +} + +#[cfg(test)] +mod tests { + use std::net::Ipv4Addr; + + use rstest::rstest; + + use super::*; + + #[rstest] + #[case::disable_rpc(&["--rpc.disabled"], |args: &mut RpcArgs| { args.rpc_disabled = true; })] + #[case::no_restart(&["--rpc.no-restart"], |args: &mut RpcArgs| { args.no_restart = true; })] + #[case::disable_rpc(&["--rpc.addr", "1.1.1.1"], |args: &mut RpcArgs| { args.listen_addr = IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)); })] + #[case::disable_rpc(&["--port", "8743"], |args: &mut RpcArgs| { args.listen_port = 8743; })] + #[case::disable_rpc_alias(&["--rpc.port", "8743"], |args: &mut RpcArgs| { args.listen_port = 8743; })] + #[case::disable_rpc(&["--rpc.enable-admin"], |args: &mut RpcArgs| { args.enable_admin = true; })] + #[case::disable_rpc(&["--rpc.admin-state", "/"], |args: &mut RpcArgs| { args.admin_persistence = Some(PathBuf::from("/")); })] + fn test_parse_rpc_args(#[case] args: &[&str], #[case] mutate: impl Fn(&mut RpcArgs)) { + let args = [&["kona-node"], args].concat(); + let cli = RpcArgs::parse_from(args); + let mut expected = RpcArgs::default(); + mutate(&mut expected); + assert_eq!(cli, expected); + } +} diff --git a/crates/client/cli/src/sequencer.rs b/crates/client/cli/src/sequencer.rs new file mode 100644 index 00000000..2ac9315c --- /dev/null +++ b/crates/client/cli/src/sequencer.rs @@ -0,0 +1,79 @@ +//! Sequencer CLI Flags +//! +//! These are based on sequencer flags from the [`op-node`][op-node] CLI. +//! +//! [op-node]: https://github.com/ethereum-optimism/optimism/blob/develop/op-node/flags/flags.go#L233-L265 + +use std::{num::ParseIntError, time::Duration}; + +use clap::Parser; +use kona_node_service::SequencerConfig; +use url::Url; + +/// Sequencer CLI Flags +#[derive(Parser, Clone, Debug, PartialEq, Eq)] +pub struct SequencerArgs { + /// Initialize the sequencer in a stopped state. The sequencer can be started using the + /// admin_startSequencer RPC. + #[arg( + long = "sequencer.stopped", + default_value = "false", + env = "KONA_NODE_SEQUENCER_STOPPED" + )] + pub stopped: bool, + + /// Maximum number of L2 blocks for restricting the distance between L2 safe and unsafe. + /// Disabled if 0. + #[arg( + long = "sequencer.max-safe-lag", + default_value = "0", + env = "KONA_NODE_SEQUENCER_MAX_SAFE_LAG" + )] + pub max_safe_lag: u64, + + /// Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 + /// origin. + #[arg(long = "sequencer.l1-confs", default_value = "4", env = "KONA_NODE_SEQUENCER_L1_CONFS")] + pub l1_confs: u64, + + /// Forces the sequencer to strictly prepare the next L1 origin and create empty L2 blocks + #[arg( + long = "sequencer.recover", + default_value = "false", + env = "KONA_NODE_SEQUENCER_RECOVER" + )] + pub recover: bool, + + /// Conductor service rpc endpoint. Providing this value will enable the conductor service. + #[arg(long = "conductor.rpc", env = "KONA_NODE_CONDUCTOR_RPC")] + pub conductor_rpc: Option, + + /// Conductor service rpc timeout. + #[arg( + long = "conductor.rpc.timeout", + default_value = "1", + env = "KONA_NODE_CONDUCTOR_RPC_TIMEOUT", + value_parser = |arg: &str| -> Result {Ok(Duration::from_secs(arg.parse()?))} + )] + pub conductor_rpc_timeout: Duration, +} + +impl Default for SequencerArgs { + fn default() -> Self { + // Construct default values using the clap parser. + // This works since none of the cli flags are required. + Self::parse_from::<[_; 0], &str>([]) + } +} + +impl SequencerArgs { + /// Creates a [`SequencerConfig`] from the [`SequencerArgs`]. + pub fn config(&self) -> SequencerConfig { + SequencerConfig { + sequencer_stopped: self.stopped, + sequencer_recovery_mode: self.recover, + conductor_rpc_url: self.conductor_rpc.clone(), + l1_conf_delay: self.l1_confs, + } + } +} diff --git a/crates/client/cli/src/signer.rs b/crates/client/cli/src/signer.rs new file mode 100644 index 00000000..ca615591 --- /dev/null +++ b/crates/client/cli/src/signer.rs @@ -0,0 +1,195 @@ +//! Signer CLI Flags for consensus clients. +//! +//! This module defines argument types for configuring block signing, +//! supporting both local private keys and remote signers. + +use std::{path::PathBuf, str::FromStr}; + +use alloy_primitives::{Address, B256}; +use alloy_signer::{Signer, k256::ecdsa}; +use alloy_signer_local::PrivateKeySigner; +use clap::Parser; +use kona_cli::SecretKeyLoader; +use kona_sources::{BlockSigner, ClientCert, RemoteSigner}; +use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +use url::Url; + +/// Signer CLI Flags +#[derive(Debug, Clone, Parser, Default, PartialEq, Eq)] +pub struct SignerArgs { + /// An optional flag to specify a local private key for the sequencer to sign unsafe blocks. + #[arg( + long = "p2p.sequencer.key", + env = "KONA_NODE_P2P_SEQUENCER_KEY", + conflicts_with = "endpoint" + )] + pub sequencer_key: Option, + /// An optional path to a file containing the sequencer private key. + /// This is mutually exclusive with `p2p.sequencer.key`. + #[arg( + long = "p2p.sequencer.key.path", + env = "KONA_NODE_P2P_SEQUENCER_KEY_PATH", + conflicts_with = "sequencer_key" + )] + pub sequencer_key_path: Option, + /// The URL of the remote signer endpoint. If not provided, remote signer will be disabled. + /// This is mutually exclusive with `p2p.sequencer.key`. + /// This is required if any of the other signer flags are provided. + #[arg( + long = "p2p.signer.endpoint", + env = "KONA_NODE_P2P_SIGNER_ENDPOINT", + requires = "address" + )] + pub endpoint: Option, + /// The address to sign transactions for. Required if `signer.endpoint` is provided. + #[arg( + long = "p2p.signer.address", + env = "KONA_NODE_P2P_SIGNER_ADDRESS", + requires = "endpoint" + )] + pub address: Option
, + /// Headers to pass to the remote signer. Format `key=value`. Value can contain any character + /// allowed in a HTTP header. When using env vars, split with commas. When using flags one + /// key value pair per flag. + #[arg(long = "p2p.signer.header", env = "KONA_NODE_P2P_SIGNER_HEADER", requires = "endpoint")] + pub header: Vec, + /// An optional path to CA certificates to be used for the remote signer. + #[arg(long = "p2p.signer.tls.ca", env = "KONA_NODE_P2P_SIGNER_TLS_CA", requires = "endpoint")] + pub ca_cert: Option, + /// An optional path to the client certificate for the remote signer. If specified, + /// `signer.tls.key` must also be specified. + #[arg( + long = "p2p.signer.tls.cert", + env = "KONA_NODE_P2P_SIGNER_TLS_CERT", + requires = "key", + requires = "endpoint" + )] + pub cert: Option, + /// An optional path to the client key for the remote signer. If specified, + /// `signer.tls.cert` must also be specified. + #[arg( + long = "p2p.signer.tls.key", + env = "KONA_NODE_P2P_SIGNER_TLS_KEY", + requires = "cert", + requires = "endpoint" + )] + pub key: Option, +} + +/// Errors that can occur when parsing the signer arguments. +#[derive(Debug, thiserror::Error)] +pub enum SignerArgsParseError { + /// The local sequencer key and remote signer cannot be specified at the same time. + #[error("A local sequencer key and a remote signer cannot be specified at the same time.")] + LocalAndRemoteSigner, + /// Both sequencer key and sequencer key path cannot be specified at the same time. + #[error( + "Both sequencer key and sequencer key path cannot be specified at the same time. Use either --p2p.sequencer.key or --p2p.sequencer.key.path." + )] + ConflictingSequencerKeyInputs, + /// The sequencer key is invalid. + #[error("The sequencer key is invalid.")] + SequencerKeyInvalid(#[from] ecdsa::Error), + /// Failed to load sequencer key from file. + #[error("Failed to load sequencer key from file")] + SequencerKeyFileError(#[from] kona_cli::KeypairError), + /// The address is required if `signer.endpoint` is provided. + #[error("The address is required if `signer.endpoint` is provided.")] + AddressRequired, + /// The header is invalid. + #[error("The header is invalid.")] + InvalidHeader, + /// The private key field is required if `signer.tls.cert` is provided. + #[error("The private key field is required if `signer.tls.cert` is provided.")] + KeyRequired, + /// The header name is invalid. + #[error("The header name is invalid.")] + InvalidHeaderName(#[from] reqwest::header::InvalidHeaderName), + /// The header value is invalid. + #[error("The header value is invalid.")] + InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue), +} + +impl SignerArgs { + /// Creates a [`BlockSigner`] from the [`SignerArgs`]. + /// + /// The `l2_chain_id` is used to set the chain ID on the signer. + pub fn config(self, l2_chain_id: u64) -> Result, SignerArgsParseError> { + // First, resolve the sequencer key from either raw input or file + let sequencer_key = self.resolve_sequencer_key()?; + + // The sequencer signer obtained from the CLI arguments. + let gossip_signer: Option = match (sequencer_key, self.config_remote()?) { + (Some(_), Some(_)) => return Err(SignerArgsParseError::LocalAndRemoteSigner), + (Some(key), None) => { + let signer: BlockSigner = + PrivateKeySigner::from_bytes(&key)?.with_chain_id(Some(l2_chain_id)).into(); + Some(signer) + } + (None, Some(signer)) => Some(signer.into()), + (None, None) => None, + }; + + Ok(gossip_signer) + } + + /// Resolves the sequencer key from either the raw key or the key file. + fn resolve_sequencer_key(&self) -> Result, SignerArgsParseError> { + match (self.sequencer_key, &self.sequencer_key_path) { + (Some(key), None) => Ok(Some(key)), + (None, Some(path)) => { + let keypair = SecretKeyLoader::load(path)?; + // Extract the private key bytes from the secp256k1 keypair + keypair.try_into_secp256k1().map_or_else( + |_| Err(SignerArgsParseError::SequencerKeyInvalid(ecdsa::Error::new())), + |secp256k1_keypair| { + let private_key_bytes = secp256k1_keypair.secret().to_bytes(); + let key = B256::from_slice(&private_key_bytes); + Ok(Some(key)) + }, + ) + } + (Some(_), Some(_)) => Err(SignerArgsParseError::ConflictingSequencerKeyInputs), + (None, None) => Ok(None), + } + } + + /// Creates a [`RemoteSigner`] from the [`SignerArgs`]. + fn config_remote(self) -> Result, SignerArgsParseError> { + let Some(endpoint) = self.endpoint else { + return Ok(None); + }; + + let Some(address) = self.address else { + return Err(SignerArgsParseError::AddressRequired); + }; + + let headers = self + .header + .iter() + .map(|h| { + let (key, value) = h.split_once('=').ok_or(SignerArgsParseError::InvalidHeader)?; + Ok((HeaderName::from_str(key)?, HeaderValue::from_str(value)?)) + }) + .collect::>()?; + + let client_cert = self + .cert + .clone() + .map(|cert| { + Ok::<_, SignerArgsParseError>(ClientCert { + cert, + key: self.key.clone().ok_or(SignerArgsParseError::KeyRequired)?, + }) + }) + .transpose()?; + + Ok(Some(RemoteSigner { + address, + endpoint, + ca_cert: self.ca_cert.clone(), + client_cert, + headers, + })) + } +} diff --git a/deny.toml b/deny.toml index 144ac394..2205496e 100644 --- a/deny.toml +++ b/deny.toml @@ -5,10 +5,6 @@ multiple-versions = "deny" # Skip crates with multiple versions from upstream dependencies that we cannot control # These are primarily from reth, alloy, and kona dependencies skip = [ - # Alloy version mismatch between workspace (0.4.x) and kona-registry (0.2.x) - "alloy-hardforks", - "alloy-op-hardforks", - # Windows platform crates - different versions used by various upstream deps "windows-sys", "windows", @@ -86,4 +82,25 @@ skip = [ "unicode-width", "unsigned-varint", "webpki-roots", + + # OpenTelemetry crates - version differences from kona dependencies + "opentelemetry", + "opentelemetry-http", + "opentelemetry-otlp", + "opentelemetry-proto", + "opentelemetry_sdk", + "tracing-opentelemetry", + + # Protobuf/gRPC crates + "prost", + "prost-derive", + "tonic", + "tower", + + # Misc + "gloo-timers", + "indexmap", + "rustc-hash", + "serde_spanned", + "toml", ]