diff --git a/Cargo.lock b/Cargo.lock index 00595b1c..dc7e03b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", @@ -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" @@ -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", @@ -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,32 @@ dependencies = [ name = "base-client-cli" version = "0.0.0" dependencies = [ - "alloy-rpc-types-engine", + "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-rpc", + "kona-sources", + "libp2p", + "reqwest", + "rollup-boost", + "rstest", + "thiserror 2.0.17", + "tokio", + "tracing", "url", ] @@ -1739,8 +1833,23 @@ name = "base-consensus" version = "0.0.0" dependencies = [ "base-cli-utils", + "base-client-cli", + "base-jwt", "clap", "eyre", + "kona-derive", + "kona-disc", + "kona-engine", + "kona-genesis", + "kona-gossip", + "kona-node-service", + "kona-providers-alloy", + "kona-registry", + "metrics", + "serde_json", + "strum 0.27.2", + "tracing", + "tracing-subscriber 0.3.22", "vergen", "vergen-git2", ] @@ -1801,7 +1910,7 @@ dependencies = [ "reth-tracing", "reth-transaction-pool", "revm 31.0.2", - "revm-database 9.0.6", + "revm-database", "rstest", "serde", "serde_json", @@ -1879,7 +1988,7 @@ dependencies = [ "reth-revm", "reth-transaction-pool", "reth-trie-common", - "revm-database 9.0.6", + "revm-database", "serde", "tokio", "tracing", @@ -2132,6 +2241,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" @@ -2434,6 +2552,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" @@ -2483,6 +2625,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -3179,6 +3322,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" @@ -3421,6 +3578,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" @@ -3880,6 +4043,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" @@ -3905,6 +4078,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -3913,6 +4087,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" @@ -3924,6 +4108,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" @@ -4267,6 +4462,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" @@ -4286,6 +4487,7 @@ dependencies = [ "rand 0.9.2", "ring", "serde", + "socket2 0.5.10", "thiserror 2.0.17", "tinyvec", "tokio", @@ -4709,6 +4911,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" @@ -4719,6 +4931,50 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +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" @@ -4881,6 +5137,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,29 +5474,93 @@ dependencies = [ ] [[package]] -name = "kona-engine" -version = "0.1.2" +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-json-rpc", - "alloy-network", "alloy-primitives", - "alloy-provider", - "alloy-rpc-client", + "alloy-rlp", "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-transport", - "alloy-transport-http", "async-trait", - "derive_more", + "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" +source = "git+https://github.com/op-rs/kona?rev=24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d#24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-trait", + "derive_more", "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", @@ -5256,41 +5579,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]] @@ -5298,6 +5646,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" @@ -5306,7 +5729,7 @@ dependencies = [ "alloc-no-stdlib", "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -5315,7 +5738,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", @@ -5325,23 +5748,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]] @@ -5365,71 +5878,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]] @@ -5878,7 +6749,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.8.0", "url", ] @@ -5901,7 +6772,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]] @@ -5930,6 +6815,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" @@ -5939,6 +6888,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" @@ -6127,6 +7093,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" @@ -6389,18 +7364,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" @@ -6467,6 +7430,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" @@ -6475,6 +7447,7 @@ checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -6827,38 +7800,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" @@ -6866,20 +7818,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]] @@ -6888,22 +7827,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" @@ -6998,6 +7928,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" @@ -7166,6 +8121,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" @@ -7304,6 +8282,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" @@ -7312,6 +8303,7 @@ checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", + "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -7530,6 +8522,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" @@ -7742,8 +8747,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", @@ -7854,7 +8859,7 @@ dependencies = [ "tar", "tokio", "tokio-stream", - "toml", + "toml 0.8.23", "tracing", "zstd", ] @@ -7928,7 +8933,7 @@ dependencies = [ "reth-prune-types", "reth-stages-types", "serde", - "toml", + "toml 0.8.23", "url", ] @@ -8397,7 +9402,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", @@ -8533,7 +9538,7 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "alloy-rlp", "bytes", @@ -8586,7 +9591,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", @@ -8811,8 +9816,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", ] @@ -8888,7 +9893,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", @@ -9183,7 +10188,7 @@ dependencies = [ "shellexpand", "strum 0.27.2", "thiserror 2.0.17", - "toml", + "toml 0.8.23", "tracing", "url", "vergen", @@ -9319,7 +10324,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-hardforks 0.4.7", + "alloy-hardforks", "alloy-primitives", "derive_more", "miniz_oxide", @@ -9485,7 +10490,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", @@ -9819,9 +10824,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", @@ -9865,8 +10870,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", @@ -9994,7 +10999,7 @@ dependencies = [ "reth-trie-common", "revm 31.0.2", "revm-inspectors", - "revm-primitives 21.0.2", + "revm-primitives", "serde", "serde_json", "sha2", @@ -10392,7 +11397,7 @@ dependencies = [ "reth-stages-types", "reth-storage-errors", "reth-trie-common", - "revm-database 9.0.6", + "revm-database", ] [[package]] @@ -10407,7 +11412,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", ] @@ -10518,7 +11523,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", @@ -10550,7 +11555,7 @@ dependencies = [ "reth-storage-errors", "reth-trie-common", "reth-trie-sparse", - "revm-database 9.0.6", + "revm-database", "tracing", "triehash", ] @@ -10577,7 +11582,7 @@ dependencies = [ "rayon", "reth-codecs", "reth-primitives-traits", - "revm-database 9.0.6", + "revm-database", "serde", "serde_with", ] @@ -10665,42 +11670,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]] @@ -10709,29 +11695,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]] @@ -10741,24 +11715,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", ] @@ -10771,11 +11729,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", ] @@ -10788,27 +11746,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", ] @@ -10822,9 +11764,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", ] @@ -10838,23 +11780,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", ] @@ -10865,23 +11793,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", ] @@ -10893,27 +11808,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", ] @@ -10925,14 +11821,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", ] @@ -10944,31 +11840,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", ] @@ -10981,11 +11860,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", ] @@ -10999,11 +11878,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", ] @@ -11026,28 +11905,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", ] @@ -11057,35 +11924,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" @@ -11104,7 +11949,7 @@ dependencies = [ "cfg-if", "k256", "p256", - "revm-primitives 21.0.2", + "revm-primitives", "ripemd", "rug", "secp256k1 0.31.1", @@ -11128,25 +11973,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" @@ -11159,18 +11992,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" @@ -11178,8 +11999,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", ] @@ -11368,6 +12189,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" @@ -11454,6 +12293,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" @@ -11584,6 +12432,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" @@ -11855,6 +12714,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" @@ -12107,6 +12975,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" @@ -12733,11 +13618,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" @@ -12764,7 +13662,7 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.13.0", "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_write", "winnow", @@ -13300,6 +14198,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" @@ -13659,6 +14563,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" @@ -13690,6 +14604,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" @@ -14189,6 +15113,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" @@ -14199,12 +15152,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 e8d0da14..77ac0166 100644 --- a/bin/consensus/Cargo.toml +++ b/bin/consensus/Cargo.toml @@ -15,10 +15,31 @@ workspace = true [dependencies] # Workspace base-cli-utils.workspace = true +base-client-cli.workspace = true +base-jwt = { workspace = true, features = ["engine-validation"] } + +# Kona +kona-genesis.workspace = true +kona-registry.workspace = true +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 +serde_json.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..50b2b9a8 100644 --- a/bin/consensus/src/cli.rs +++ b/bin/consensus/src/cli.rs @@ -1,7 +1,21 @@ //! Contains the CLI entry point for the Base consensus binary. -use base_cli_utils::GlobalArgs; +use std::{fs::File, path::PathBuf, sync::Arc, time::Duration}; + +use base_cli_utils::{CliStyles, GlobalArgs, LogConfig, RuntimeManager}; +use base_client_cli::{ + BuilderClientArgs, JwtSecret, L1ClientArgs, L2ClientArgs, P2PArgs, RollupBoostFlags, RpcArgs, + SequencerArgs, +}; +use base_jwt::JwtValidator; use clap::Parser; +use eyre::bail; +use kona_genesis::{L1ChainConfig, RollupConfig}; +use kona_node_service::{EngineConfig, L1ConfigBuilder, NodeMode, RollupNodeBuilder}; +use kona_registry::{L1Config, scr_rollup_config_by_alloy_ident}; +use serde_json::from_reader; +use strum::IntoEnumIterator; +use tracing::{debug, error, info}; use crate::version; @@ -11,6 +25,7 @@ use crate::version; author, version = version::SHORT_VERSION, long_version = version::LONG_VERSION, + styles = CliStyles::init(), about, long_about = None )] @@ -18,17 +33,209 @@ 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, + + /// 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, + /// Path to a custom L1 rollup configuration file + /// (overrides the default rollup configuration from the registry) + #[arg(long, visible_alias = "rollup-l1-cfg", env = "KONA_NODE_L1_CHAIN_CONFIG")] + pub l1_config_file: Option, + /// 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.get_l2_config(args)?; + + 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_config = L1ConfigBuilder { + chain_config: self.get_l1_config(cfg.l1_chain_id)?, + 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.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(()) } + + /// 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.l2_client_args.jwt_secret().map_err(|e| eyre::eyre!(e))?; + let validator = JwtValidator::new(jwt_secret); + validator + .validate_with_engine(self.l2_client_args.l2_engine_rpc.clone()) + .await + .map_err(|e| eyre::eyre!(e)) + } + + /// Get the L1 config, either from a file or the known chains. + pub fn get_l1_config(&self, l1_chain_id: u64) -> eyre::Result { + match &self.l1_config_file { + Some(path) => { + debug!("Loading l1 config from file: {:?}", path); + let file = File::open(path) + .map_err(|e| eyre::eyre!("Failed to open l1 config file: {e}"))?; + from_reader(file).map_err(|e| eyre::eyre!("Failed to parse l1 config: {e}")) + } + None => { + debug!("Loading l1 config from known chains"); + let cfg = L1Config::get_l1_genesis(l1_chain_id).map_err(|e| { + eyre::eyre!("Failed to find l1 config for chain ID {l1_chain_id}: {e}") + })?; + Ok(cfg.into()) + } + } + } + + /// Get the L2 rollup config, either from a file or the superchain registry. + pub fn get_l2_config(&self, args: &GlobalArgs) -> eyre::Result { + match &self.l2_config_file { + Some(path) => { + debug!("Loading l2 config from file: {:?}", path); + let file = File::open(path) + .map_err(|e| eyre::eyre!("Failed to open l2 config file: {e}"))?; + from_reader(file).map_err(|e| eyre::eyre!("Failed to parse l2 config: {e}")) + } + None => { + debug!("Loading l2 config from superchain registry"); + let Some(cfg) = scr_rollup_config_by_alloy_ident(&args.l2_chain_id) else { + bail!("Failed to find l2 config for chain ID {}", args.l2_chain_id); + }; + Ok(cfg.clone()) + } + } + } + + /// 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 75778ec1..6932760a 100644 --- a/bin/consensus/src/main.rs +++ b/bin/consensus/src/main.rs @@ -4,10 +4,11 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] pub mod cli; - -pub(crate) mod version; +pub mod version; fn main() { + use clap::Parser; + base_cli_utils::Backtracing::enable(); base_cli_utils::SigsegvHandler::install(); diff --git a/bin/consensus/src/version.rs b/bin/consensus/src/version.rs index 75874a4e..af57c214 100644 --- a/bin/consensus/src/version.rs +++ b/bin/consensus/src/version.rs @@ -1,7 +1,95 @@ //! Version information for the Base binary. +//! +//! [`VersionInfo`] metrics. +//! +//! Derived from [`reth-node-core`'s type][reth-version-info] +//! +//! [reth-version-info]: https://github.com/paradigmxyz/reth/blob/805fb1012cd1601c3b4fe9e8ca2d97c96f61355b/crates/node/metrics/src/version.rs#L6 + +use metrics::gauge; + +/// Cargo package version. +pub const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Build timestamp from vergen. +pub const VERGEN_BUILD_TIMESTAMP: &str = env!("VERGEN_BUILD_TIMESTAMP"); + +/// Cargo features from vergen. +pub const VERGEN_CARGO_FEATURES: &str = env!("VERGEN_CARGO_FEATURES"); + +/// Git SHA from vergen. +pub const VERGEN_GIT_SHA: &str = env!("VERGEN_GIT_SHA"); + +/// Cargo target triple from vergen. +pub const VERGEN_CARGO_TARGET_TRIPLE: &str = env!("VERGEN_CARGO_TARGET_TRIPLE"); + +/// Build profile name. +pub const BUILD_PROFILE_NAME: &str = env!("BASE_CONSENSUS_BUILD_PROFILE"); /// Short version string. -pub(crate) const SHORT_VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const SHORT_VERSION: &str = env!("BASE_CONSENSUS_SHORT_VERSION"); /// Long version string with additional build info. -pub(crate) const LONG_VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\n", "Base Stack CLI"); +pub const LONG_VERSION: &str = concat!( + env!("BASE_CONSENSUS_LONG_VERSION_0"), + "\n", + env!("BASE_CONSENSUS_LONG_VERSION_1"), + "\n", + env!("BASE_CONSENSUS_LONG_VERSION_2"), + "\n", + env!("BASE_CONSENSUS_LONG_VERSION_3"), + "\n", + env!("BASE_CONSENSUS_LONG_VERSION_4") +); + +/// Contains version information for the application and allows for exposing the contained +/// information as a prometheus metric. +#[derive(Debug, Clone)] +pub struct VersionInfo { + /// The version of the application. + pub version: &'static str, + /// The build timestamp of the application. + pub build_timestamp: &'static str, + /// The cargo features enabled for the build. + pub cargo_features: &'static str, + /// The Git SHA of the build. + pub git_sha: &'static str, + /// The target triple for the build. + pub target_triple: &'static str, + /// The build profile (e.g., debug or release). + pub build_profile: &'static str, +} + +impl VersionInfo { + /// Creates a new instance of [`VersionInfo`] from the constants defined in [`crate::version`] + /// at compile time. + pub const fn from_build() -> Self { + Self { + version: CARGO_PKG_VERSION, + build_timestamp: VERGEN_BUILD_TIMESTAMP, + cargo_features: VERGEN_CARGO_FEATURES, + git_sha: VERGEN_GIT_SHA, + target_triple: VERGEN_CARGO_TARGET_TRIPLE, + build_profile: BUILD_PROFILE_NAME, + } + } + + /// Exposes kona-node's version information over prometheus. + pub fn register_version_metrics(&self) { + // If no features are enabled, the string will be empty, and the metric will not be + // reported. Report "none" if the string is empty. + let features = if self.cargo_features.is_empty() { "none" } else { self.cargo_features }; + + let labels: [(&str, &str); 6] = [ + ("version", self.version), + ("build_timestamp", self.build_timestamp), + ("cargo_features", features), + ("git_sha", self.git_sha), + ("target_triple", self.target_triple), + ("build_profile", self.build_profile), + ]; + + let gauge = gauge!("kona_node_info", &labels); + gauge.set(1); + } +} diff --git a/crates/client/cli/Cargo.toml b/crates/client/cli/Cargo.toml index 463d0954..45eabab0 100644 --- a/crates/client/cli/Cargo.toml +++ b/crates/client/cli/Cargo.toml @@ -12,7 +12,41 @@ repository.workspace = true workspace = true [dependencies] -# General +# Shared +base-jwt.workspace = true + +# 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"] } +rollup-boost-kona.workspace = true + +# Alloy +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/l2.rs b/crates/client/cli/src/l2.rs index ed0198d8..f9ba1623 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, resolve_jwt_secret}; use url::Url; const DEFAULT_L2_ENGINE_TIMEOUT: u64 = 30_000; @@ -51,3 +51,19 @@ 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", + ) + } +} diff --git a/crates/client/cli/src/lib.rs b/crates/client/cli/src/lib.rs index ad91a070..e3304acb 100644 --- a/crates/client/cli/src/lib.rs +++ b/crates/client/cli/src/lib.rs @@ -8,3 +8,22 @@ 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", ]