From 2e379752dba4afd8aaf233bf3fd30c55b6734c16 Mon Sep 17 00:00:00 2001 From: refcell Date: Thu, 13 Feb 2025 12:15:01 -0500 Subject: [PATCH] kona networking crate --- Cargo.lock | 2120 ++++++++++++++++- Cargo.toml | 12 + book/src/sdk/pipeline/intro.md | 2 +- crates/protocol/interop/src/graph.rs | 6 +- crates/services/net/Cargo.toml | 49 + crates/services/net/README.md | 46 + crates/services/net/src/builder.rs | 494 ++++ .../services/net/src/discovery/bootnodes.rs | 35 + crates/services/net/src/discovery/builder.rs | 117 + crates/services/net/src/discovery/driver.rs | 118 + crates/services/net/src/discovery/mod.rs | 5 + crates/services/net/src/driver.rs | 69 + crates/services/net/src/gossip/behaviour.rs | 91 + crates/services/net/src/gossip/config.rs | 118 + crates/services/net/src/gossip/driver.rs | 92 + crates/services/net/src/gossip/event.rs | 27 + crates/services/net/src/gossip/handler.rs | 129 + crates/services/net/src/gossip/mod.rs | 7 + crates/services/net/src/lib.rs | 14 + crates/services/net/src/types/enr.rs | 118 + crates/services/net/src/types/mod.rs | 4 + crates/services/net/src/types/peer.rs | 141 ++ crates/services/providers-alloy/Cargo.toml | 2 +- crates/services/providers-alloy/src/lib.rs | 6 +- justfile | 4 +- 25 files changed, 3724 insertions(+), 102 deletions(-) create mode 100644 crates/services/net/Cargo.toml create mode 100644 crates/services/net/README.md create mode 100644 crates/services/net/src/builder.rs create mode 100644 crates/services/net/src/discovery/bootnodes.rs create mode 100644 crates/services/net/src/discovery/builder.rs create mode 100644 crates/services/net/src/discovery/driver.rs create mode 100644 crates/services/net/src/discovery/mod.rs create mode 100644 crates/services/net/src/driver.rs create mode 100644 crates/services/net/src/gossip/behaviour.rs create mode 100644 crates/services/net/src/gossip/config.rs create mode 100644 crates/services/net/src/gossip/driver.rs create mode 100644 crates/services/net/src/gossip/event.rs create mode 100644 crates/services/net/src/gossip/handler.rs create mode 100644 crates/services/net/src/gossip/mod.rs create mode 100644 crates/services/net/src/lib.rs create mode 100644 crates/services/net/src/types/enr.rs create mode 100644 crates/services/net/src/types/mod.rs create mode 100644 crates/services/net/src/types/peer.rs diff --git a/Cargo.lock b/Cargo.lock index 0630b1821..69ebf5dbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,41 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.11" @@ -71,9 +106,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c00207aa710b43a3a81fbd882aee05bdab0c02d38f559c25704bfd3a00ecc7" +checksum = "3a754dbb534198644cb8355b8c23f4aaecf03670fb9409242be1fa1e25897ee9" dependencies = [ "alloy-primitives", "num_enum", @@ -163,9 +198,11 @@ dependencies = [ "auto_impl", "c-kzg", "derive_more", + "ethereum_ssz", + "ethereum_ssz_derive", "once_cell", "serde", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -246,6 +283,7 @@ dependencies = [ "derive_arbitrary", "derive_more", "foldhash", + "getrandom 0.2.15", "hashbrown 0.15.2", "indexmap", "itoa", @@ -289,7 +327,7 @@ dependencies = [ "dashmap", "futures", "futures-utils-wasm", - "lru", + "lru 0.13.0", "parking_lot", "pin-project", "reqwest", @@ -429,6 +467,8 @@ dependencies = [ "alloy-rlp", "alloy-serde", "derive_more", + "ethereum_ssz", + "ethereum_ssz_derive", "serde", "strum", ] @@ -556,7 +596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a8d762eadce3e9b65eac09879430c6f4fce3736cac3cac123f9b1bf435ddd13" dependencies = [ "alloy-json-rpc", - "base64", + "base64 0.22.1", "futures-utils-wasm", "serde", "serde_json", @@ -612,7 +652,7 @@ dependencies = [ "alloy-pubsub", "alloy-transport", "futures", - "http", + "http 1.2.0", "rustls", "serde_json", "tokio", @@ -708,6 +748,15 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arbtest" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3be567977128c0f71ad1462d9624ccda712193d124e944252f0c5789a06d46" +dependencies = [ + "arbitrary", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -832,6 +881,12 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -841,6 +896,51 @@ dependencies = [ "serde", ] +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "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.98", +] + +[[package]] +name = "asn1_der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" + [[package]] name = "async-channel" version = "2.3.1" @@ -853,6 +953,36 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -897,12 +1027,36 @@ 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.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http 0.2.12", + "log", + "url", +] + [[package]] name = "aurora-engine-modexp" version = "1.2.0" @@ -942,15 +1096,27 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base16ct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.22.1" @@ -1028,6 +1194,24 @@ 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.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1070,6 +1254,15 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -1184,6 +1377,36 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +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.39" @@ -1221,6 +1444,17 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1342,6 +1576,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpp_demangle" version = "0.4.4" @@ -1461,9 +1704,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "darling" version = "0.20.10" @@ -1519,6 +1809,26 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +[[package]] +name = "data-encoding-macro" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9724adfcf41f45bf652b3995837669d73c4d49a1b5ac1ff82905ac7d9b5558" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e4fdb82bd54a12e42fb58a800dcae6b9e13982238ce2296dc3570b92148e1f" +dependencies = [ + "data-encoding", + "syn 2.0.98", +] + [[package]] name = "debugid" version = "0.8.0" @@ -1528,6 +1838,17 @@ dependencies = [ "uuid", ] +[[package]] +name = "delay_map" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df941644b671f05f59433e481ba0d31ac10e3667de725236a4c0d587c496fba1" +dependencies = [ + "futures", + "tokio", + "tokio-util", +] + [[package]] name = "der" version = "0.7.9" @@ -1538,6 +1859,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.3.11" @@ -1605,12 +1940,43 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "discv5" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4b4e7798d2ff74e29cee344dc490af947ae657d6ab5273dde35d58ce06a4d71" +dependencies = [ + "aes", + "aes-gcm", + "alloy-rlp", + "arrayvec", + "ctr", + "delay_map", + "enr", + "fnv", + "futures", + "hashlink", + "hex", + "hkdf", + "lazy_static", + "lru 0.12.5", + "more-asserts", + "parking_lot", + "rand 0.8.5", + "smallvec", + "socket2", + "tokio", + "tracing", + "uint 0.10.0", + "zeroize", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1629,7 +1995,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" [[package]] -name = "dunce" +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dunce" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" @@ -1654,6 +2026,31 @@ dependencies = [ "spki", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.13.0" @@ -1688,6 +2085,37 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enr" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851bd664a3d3a3c175cff92b2f0df02df3c541b4895d0ae307611827aae46152" +dependencies = [ + "alloy-rlp", + "base64 0.22.1", + "bytes", + "ed25519-dalek", + "hex", + "k256", + "log", + "rand 0.8.5", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "enumn" version = "0.1.14" @@ -1735,6 +2163,46 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "ethereum_serde_utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70cbccfccf81d67bff0ab36e591fa536c8a935b078a7b0e58c1d00d418332fc9" +dependencies = [ + "alloy-primitives", + "hex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "ethereum_ssz" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86da3096d1304f5f28476ce383005385459afeaf0eea08592b65ddbc9b258d16" +dependencies = [ + "alloy-primitives", + "ethereum_serde_utils", + "itertools 0.13.0", + "serde", + "serde_derive", + "smallvec", + "typenum", +] + +[[package]] +name = "ethereum_ssz_derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832a5c38eba0e7ad92592f7a22d693954637fbb332b4f669590d66a5c3183e5" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "event-listener" version = "5.4.0" @@ -1783,6 +2251,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "findshlibs" version = "0.10.2" @@ -1889,6 +2363,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -1897,6 +2372,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -1908,6 +2393,17 @@ dependencies = [ "syn 2.0.98", ] +[[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" @@ -1920,6 +2416,17 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-ticker" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9763058047f713632a52e916cc7f6a4b3fc6e9fc1ff8c5b1dc49e5a89041682e" +dependencies = [ + "futures", + "futures-timer", + "instant", +] + [[package]] name = "futures-timer" version = "3.0.3" @@ -1968,8 +2475,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1981,7 +2490,17 @@ dependencies = [ "cfg-if", "libc", "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", ] [[package]] @@ -2007,6 +2526,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.7" @@ -2018,7 +2556,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.2.0", "indexmap", "slab", "tokio", @@ -2041,6 +2579,9 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -2054,6 +2595,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "heck" version = "0.5.0" @@ -2081,6 +2631,77 @@ dependencies = [ "serde", ] +[[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.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad3d6d98c648ed628df039541a5577bee1a7c83e9e16fe3dbedeea4cdfeb971" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "socket2", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf287bde7b776e85d7188e6e5db7cf410a2f9531fe82817eb87feed034c8d14" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + [[package]] name = "hmac" version = "0.12.1" @@ -2090,6 +2711,39 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.2.0" @@ -2101,6 +2755,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -2108,7 +2773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.2.0", ] [[package]] @@ -2119,8 +2784,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http", - "http-body", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2130,6 +2795,36 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.6.0" @@ -2139,9 +2834,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -2157,8 +2852,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http", - "hyper", + "http 1.2.0", + "hyper 1.6.0", "hyper-util", "rustls", "rustls-pki-types", @@ -2175,7 +2870,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-util", "native-tls", "tokio", @@ -2192,9 +2887,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", - "hyper", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.6.0", "pin-project-lite", "socket2", "tokio", @@ -2348,22 +3043,74 @@ dependencies = [ ] [[package]] -name = "impl-codec" -version = "0.6.0" +name = "if-addrs" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" dependencies = [ - "parity-scale-codec", + "libc", + "windows-sys 0.48.0", ] [[package]] -name = "impl-trait-for-tuples" -version = "0.2.3" +name = "if-watch" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" dependencies = [ - "proc-macro2", - "quote", + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-proto", + "netlink-sys", + "rtnetlink", + "system-configuration", + "tokio", + "windows", +] + +[[package]] +name = "igd-next" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rand 0.8.5", + "tokio", + "url", + "xmltree", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", "syn 2.0.98", ] @@ -2397,6 +3144,24 @@ dependencies = [ "str_stack", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "interprocess" version = "2.2.2" @@ -2412,6 +3177,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -2453,6 +3230,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2497,7 +3283,8 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2", + "sha2 0.10.8", + "signature", ] [[package]] @@ -2540,7 +3327,7 @@ dependencies = [ "kona-proof-interop", "kona-std-fpvm", "kona-std-fpvm-proc", - "lru", + "lru 0.13.0", "maili-genesis", "maili-protocol", "maili-registry", @@ -2549,7 +3336,7 @@ dependencies = [ "revm", "serde", "serde_json", - "spin", + "spin 0.9.8", "thiserror 2.0.11", "tracing", ] @@ -2572,7 +3359,7 @@ dependencies = [ "op-alloy-rpc-types-engine", "proptest", "serde_json", - "spin", + "spin 0.9.8", "thiserror 2.0.11", "tokio", "tracing", @@ -2594,7 +3381,7 @@ dependencies = [ "maili-rpc", "op-alloy-consensus", "op-alloy-rpc-types-engine", - "spin", + "spin 0.9.8", "thiserror 2.0.11", "tracing", ] @@ -2718,6 +3505,29 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "kona-net" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-engine", + "arbitrary", + "arbtest", + "discv5", + "futures", + "lazy_static", + "libp2p", + "libp2p-identity", + "op-alloy-rpc-types-engine", + "openssl", + "snap", + "thiserror 2.0.11", + "tokio", + "tracing", + "unsigned-varint 0.8.0", +] + [[package]] name = "kona-preimage" version = "0.2.1" @@ -2746,7 +3556,7 @@ dependencies = [ "kona-executor", "kona-mpt", "kona-preimage", - "lru", + "lru 0.13.0", "maili-genesis", "maili-protocol", "maili-registry", @@ -2755,7 +3565,7 @@ dependencies = [ "op-alloy-rpc-types-engine", "serde", "serde_json", - "spin", + "spin 0.9.8", "thiserror 2.0.11", "tokio", "tracing", @@ -2784,7 +3594,7 @@ dependencies = [ "rand 0.9.0", "serde", "serde_json", - "spin", + "spin 0.9.8", "thiserror 2.0.11", "tracing", ] @@ -2803,7 +3613,7 @@ dependencies = [ "alloy-transport", "async-trait", "kona-derive", - "lru", + "lru 0.13.0", "maili-genesis", "maili-protocol", "op-alloy-consensus", @@ -2842,7 +3652,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -2855,30 +3665,438 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libp2p" +version = "0.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbe80f9c7e00526cd6b838075b9c171919404a4732cb2fa8ece0a093223bfc4" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom 0.2.15", + "libp2p-allow-block-list", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-dns", + "libp2p-gossipsub", + "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 1.0.69", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1027ccf8d70320ed77e984f273bc8ce952f623762cb9bf2d126df73caef8041" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d003540ee8baef0d254f7b6bfd79bac3ddf774662ca0abf69186d517ef82ad8" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", +] + +[[package]] +name = "libp2p-core" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61f26c83ed111104cd820fe9bc3aaabbac5f1652a1d213ed6e900b7918a1298" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr", + "multihash", + "multistream-select", + "once_cell", + "parking_lot", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink", + "smallvec", + "thiserror 1.0.69", + "tracing", + "unsigned-varint 0.8.0", + "void", + "web-time", +] + +[[package]] +name = "libp2p-dns" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97f37f30d5c7275db282ecd86e54f29dd2176bd3ac656f06abf43bedb21eb8bd" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4e830fdf24ac8c444c12415903174d506e1e077fbe3875c404a78c5935a8543" +dependencies = [ + "asynchronous-codec", + "base64 0.22.1", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-ticker", + "getrandom 0.2.15", + "hex_fmt", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.5", + "regex", + "sha2 0.10.8", + "smallvec", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "hkdf", + "libsecp256k1", + "multihash", + "quick-protobuf", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror 1.0.69", + "tracing", + "zeroize", +] + +[[package]] +name = "libp2p-mdns" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b8546b6644032565eb29046b42744aee1e9f261ed99671b2c93fb140dba417" +dependencies = [ + "data-encoding", + "futures", + "hickory-proto", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "smallvec", + "socket2", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-metrics" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ebafa94a717c8442d8db8d3ae5d1c6a15e30f2d347e0cd31d057ca72e42566" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-gossipsub", + "libp2p-identity", + "libp2p-ping", + "libp2p-swarm", + "pin-project", + "prometheus-client", + "web-time", +] + +[[package]] +name = "libp2p-noise" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b137cb1ae86ee39f8e5d6245a296518912014eaa87427d24e6ff58cfc1b28c" +dependencies = [ + "asynchronous-codec", + "bytes", + "curve25519-dalek", + "futures", + "libp2p-core", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand 0.8.5", + "sha2 0.10.8", + "snow", + "static_assertions", + "thiserror 1.0.69", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "libp2p-ping" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005a34420359223b974ee344457095f027e51346e992d1e0dcd35173f4cdd422" +dependencies = [ + "either", + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-quic" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46352ac5cd040c70e88e7ff8257a2ae2f891a4076abad2c439584a31c15fd24e" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "parking_lot", + "quinn", + "rand 0.8.5", + "ring 0.17.8", + "rustls", + "socket2", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-swarm" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dd6741793d2c1fb2088f67f82cf07261f25272ebe3c0b0c311e0c6b50e851a" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm-derive", + "lru 0.12.5", + "multistream-select", + "once_cell", + "rand 0.8.5", + "smallvec", + "tokio", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "libp2p-tcp" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad964f312c59dcfcac840acd8c555de8403e295d39edf96f5240048b5fcaa314" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core", + "libp2p-identity", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b23dddc2b9c355f73c1e36eb0c3ae86f7dc964a3715f0731cfad352db4d847" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core", + "libp2p-identity", + "rcgen", + "ring 0.17.8", + "rustls", + "rustls-webpki 0.101.7", + "thiserror 1.0.69", + "x509-parser", + "yasna", +] + +[[package]] +name = "libp2p-upnp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01bf2d1b772bd3abca049214a3304615e6a36fa6ffc742bdd1ba774486200b8f" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core", + "libp2p-swarm", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-yamux" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788b61c80789dba9760d8c669a5bedb642c8267555c803fabd8396e4ca5c5882" +dependencies = [ + "either", + "futures", + "libp2p-core", + "thiserror 1.0.69", + "tracing", + "yamux 0.12.1", + "yamux 0.13.4", +] + +[[package]] +name = "librocksdb-sys" +version = "0.16.0+8.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce3d60bc059831dc1c83903fb45c103f75db65c5a7bf22272764d9cc683e348c" +dependencies = [ + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] [[package]] -name = "libloading" -version = "0.8.6" +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" dependencies = [ - "cfg-if", - "windows-targets", + "libsecp256k1-core", ] [[package]] -name = "librocksdb-sys" -version = "0.16.0+8.10.0" +name = "libsecp256k1-gen-genmult" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3d60bc059831dc1c83903fb45c103f75db65c5a7bf22272764d9cc683e348c" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", + "libsecp256k1-core", ] [[package]] @@ -2892,6 +4110,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -2929,6 +4153,15 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "lru" version = "0.13.0" @@ -2938,6 +4171,15 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "maili-genesis" version = "0.2.8" @@ -2979,7 +4221,7 @@ dependencies = [ "thiserror 2.0.11", "tracing", "tracing-subscriber", - "unsigned-varint", + "unsigned-varint 0.8.0", ] [[package]] @@ -3020,6 +4262,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "memchr" version = "2.7.4" @@ -3067,6 +4315,66 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "more-asserts" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" + +[[package]] +name = "multiaddr" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "libp2p-identity", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.8.0", + "url", +] + +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" +dependencies = [ + "core2", + "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]] name = "munge" version = "0.4.1" @@ -3104,6 +4412,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.11", +] + +[[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 = "nix" version = "0.26.4" @@ -3115,6 +4487,12 @@ dependencies = [ "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" @@ -3274,6 +4652,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.20.3" @@ -3353,11 +4740,19 @@ dependencies = [ "alloy-rpc-types-engine", "alloy-serde", "derive_more", + "ethereum_ssz", "op-alloy-consensus", "serde", + "snap", "thiserror 2.0.11", ] +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.70" @@ -3390,6 +4785,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-src" +version = "300.4.2+3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.105" @@ -3398,6 +4802,7 @@ checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -3417,7 +4822,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -3474,7 +4879,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3483,6 +4888,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -3586,6 +5001,44 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3641,7 +5094,7 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "uint", + "uint 0.9.5", ] [[package]] @@ -3684,6 +5137,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prometheus-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" +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.98", +] + [[package]] name = "proptest" version = "1.6.0" @@ -3741,6 +5217,28 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +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 = "quick-xml" version = "0.26.0" @@ -3750,6 +5248,59 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring 0.17.8", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.38" @@ -3859,10 +5410,22 @@ dependencies = [ name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rcgen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" dependencies = [ - "crossbeam-deque", - "crossbeam-utils", + "pem", + "ring 0.16.20", + "time", + "yasna", ] [[package]] @@ -3930,16 +5493,16 @@ version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-rustls", "hyper-tls", "hyper-util", @@ -3968,6 +5531,16 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "revm" version = "19.5.0" @@ -4010,7 +5583,7 @@ dependencies = [ "revm-primitives", "ripemd", "secp256k1", - "sha2", + "sha2 0.10.8", "substrate-bn", ] @@ -4040,7 +5613,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] @@ -4053,6 +5626,21 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -4063,8 +5651,8 @@ dependencies = [ "cfg-if", "getrandom 0.2.15", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -4157,6 +5745,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 = "ruint" version = "1.12.3" @@ -4230,6 +5836,15 @@ dependencies = [ "semver 1.0.25", ] +[[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" @@ -4250,9 +5865,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "once_cell", - "ring", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -4271,6 +5886,19 @@ name = "rustls-pki-types" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] [[package]] name = "rustls-webpki" @@ -4278,9 +5906,9 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4301,6 +5929,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.19" @@ -4488,7 +6127,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "serde", @@ -4521,6 +6160,19 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.8" @@ -4610,6 +6262,29 @@ dependencies = [ "serde", ] +[[package]] +name = "snap" +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 0.17.8", + "rustc_version 0.4.1", + "sha2 0.10.8", + "subtle", +] + [[package]] name = "socket2" version = "0.5.8" @@ -4620,6 +6295,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -4897,10 +6578,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", "time-core", + "time-macros", ] [[package]] @@ -4909,6 +6592,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -5040,6 +6733,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", + "slab", "tokio", ] @@ -5110,6 +6804,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5177,7 +6872,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 1.2.0", "httparse", "log", "rand 0.8.5", @@ -5212,6 +6907,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unarray" version = "0.1.4" @@ -5230,12 +6937,34 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsigned-varint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" + [[package]] name = "unsigned-varint" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -5301,6 +7030,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "wait-timeout" version = "0.2.1" @@ -5439,6 +7174,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.26.8" @@ -5485,15 +7230,44 @@ 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", + "windows-targets 0.52.6", +] + +[[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-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -5502,7 +7276,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -5511,8 +7285,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", - "windows-targets", + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -5521,7 +7304,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -5530,7 +7313,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -5539,28 +7337,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5573,24 +7389,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5606,6 +7446,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wit-bindgen-rt" version = "0.33.0" @@ -5655,6 +7505,90 @@ 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.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand 0.8.5", + "static_assertions", + "web-time", +] + +[[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.7.5" diff --git a/Cargo.toml b/Cargo.toml index 7b979679b..b3b33d1ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ kona-driver = { path = "crates/protocol/driver", version = "0.2.3", default-feat kona-interop = { path = "crates/protocol/interop", version = "0.1.1", default-features = false } # Workspace Services +kona-net = { path = "crates/services/net", version = "0.1.0", default-features = false } kona-providers-alloy = { path = "crates/services/providers-alloy", version = "0.1.0", default-features = false } # Workspace Proof @@ -116,11 +117,14 @@ clap = "4.5.29" tokio = "1.43.0" cfg-if = "1.0.0" rstest = "0.24.0" +futures = "0.3.31" reqwest = "0.12.12" tempfile = "3.16.0" +arbitrary = "1.4.1" async-trait = "0.1.86" async-channel = "2.3.1" linked_list_allocator = "0.10.5" +lazy_static = { version = "1.5.0", default-features = false } # General sha2 = { version = "0.10.8", default-features = false } @@ -128,6 +132,13 @@ c-kzg = { version = "2.0.0", default-features = false } anyhow = { version = "1.0.95", default-features = false } thiserror = { version = "2.0.11", default-features = false } +# Networking +snap = "1.1.1" +discv5 = "0.9.1" +libp2p = "0.54.1" +openssl = "0.10.70" +libp2p-identity = "0.2.10" + # Tracing tracing-loki = "0.2.6" tracing-subscriber = "0.3.19" @@ -135,6 +146,7 @@ tracing = { version = "0.1.41", default-features = false } # Testing pprof = "0.14.0" +arbtest = "0.3.2" proptest = "1.6.0" criterion = "0.5.1" diff --git a/book/src/sdk/pipeline/intro.md b/book/src/sdk/pipeline/intro.md index 0c2735263..0c8f1e44a 100644 --- a/book/src/sdk/pipeline/intro.md +++ b/book/src/sdk/pipeline/intro.md @@ -95,7 +95,7 @@ the [`PipelineBuilder`][builder] to instantiate a [`DerivationPipeline`][dp]. use std::sync::Arc; use maili_protocol::BlockInfo; use maili_genesis::RollupConfig; -use hilo_providers_alloy::*; +use kona_providers_alloy::*; // Use a default rollup config. let rollup_config = Arc::new(RollupConfig::default()); diff --git a/crates/protocol/interop/src/graph.rs b/crates/protocol/interop/src/graph.rs index 298211555..f673059d4 100644 --- a/crates/protocol/interop/src/graph.rs +++ b/crates/protocol/interop/src/graph.rs @@ -340,10 +340,8 @@ mod test { let (headers, provider) = superchain.build(); - let cfgs = HashMap::from([( - 0xDEAD, - RollupConfig { interop_time: Some(50), ..Default::default() }, - )]); + let mut cfgs = HashMap::default(); + cfgs.insert(0xDEAD, RollupConfig { interop_time: Some(50), ..Default::default() }); let graph = MessageGraph::derive(headers.as_slice(), &provider, &cfgs).await.unwrap(); assert_eq!( graph.resolve().await.unwrap_err(), diff --git a/crates/services/net/Cargo.toml b/crates/services/net/Cargo.toml new file mode 100644 index 000000000..7aede3ca0 --- /dev/null +++ b/crates/services/net/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "kona-net" +version = "0.1.0" +description = "Consensus networking library for the OP Stack" + +edition.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +repository.workspace = true +rust-version.workspace = true + +[dependencies] +# Alloy +alloy-rlp.workspace = true +alloy-primitives = { workspace = true, features = ["k256", "getrandom"] } +alloy-rpc-types-engine = { workspace = true, features = ["std"] } + +# Op Alloy +op-alloy-rpc-types-engine = { workspace = true, features = ["std"] } + +# Networking +snap.workspace = true +futures.workspace = true +discv5.workspace = true +libp2p = { workspace = true, features = ["macros", "tokio", "tcp", "noise", "gossipsub", "ping", "yamux"] } +openssl = { workspace = true, features = ["vendored"] } +libp2p-identity = { workspace = true, features = ["secp256k1"] } + +# Misc +tokio.workspace = true +tracing.workspace = true +thiserror.workspace = true +lazy_static.workspace = true +unsigned-varint.workspace = true + +# `arbitrary` feature dependencies +arbitrary = { workspace = true, features = ["derive"], optional = true } + +[dev-dependencies] +arbtest.workspace = true +arbitrary = { workspace = true, features = ["derive"] } +alloy-primitives = { workspace = true, features = ["arbitrary"] } + +[features] +default = [] +arbitrary = ["dep:arbitrary", "alloy-primitives/arbitrary"] diff --git a/crates/services/net/README.md b/crates/services/net/README.md new file mode 100644 index 000000000..d5c919a5c --- /dev/null +++ b/crates/services/net/README.md @@ -0,0 +1,46 @@ +# `kona-net` + +A consensus network library for the OP Stack. + +Contains a gossipsub driver to run discv5 peer discovery and block gossip. + +### Example + +> **Warning** +> +> Notice, the socket address uses `0.0.0.0`. +> If you are experiencing issues connecting to peers for discovery, +> check to make sure you are not using the loopback address, +> `127.0.0.1` aka "localhost", which can prevent outward facing connections. + +```rust,no_run +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use alloy_primitives::address; +use kona_net::driver::NetworkDriver; + +// Build the network driver. +let signer = address!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); +let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); +let driver = NetworkDriver::builder() + .with_chain_id(10) // op mainnet chain id + .with_unsafe_block_signer(signer) + .with_gossip_addr(socket) + .build() + .expect("Failed to builder network driver"); + +// Call `.start()` on the driver. +driver.start().expect("Failed to start network driver"); + +println!("NetworkDriver started."); +``` + +[!WARNING]: ###example + +### Acknowledgements + +Largely based off [magi]'s [p2p module][p2p]. + + + +[magi]: https://github.com/a16z/magi +[p2p]: https://github.com/a16z/magi/tree/master/src/network diff --git a/crates/services/net/src/builder.rs b/crates/services/net/src/builder.rs new file mode 100644 index 000000000..6986ce6e1 --- /dev/null +++ b/crates/services/net/src/builder.rs @@ -0,0 +1,494 @@ +//! Network Builder Module. + +use alloy_primitives::Address; +use discv5::{Config, ListenConfig}; +use std::{ + net::{IpAddr, SocketAddr}, + time::Duration, +}; +use tokio::sync::watch::channel; + +use libp2p::{ + gossipsub::Config as GossipConfig, multiaddr::Protocol, noise::Config as NoiseConfig, + tcp::Config as TcpConfig, yamux::Config as YamuxConfig, Multiaddr, SwarmBuilder, +}; +use libp2p_identity::Keypair; + +use crate::{ + discovery::builder::{DiscoveryBuilder, DiscoveryBuilderError}, + driver::NetworkDriver, + gossip::{ + behaviour::{Behaviour, BehaviourError}, + config, + driver::GossipDriver, + handler::BlockHandler, + }, +}; + +/// An error from the [NetworkDriverBuilder]. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum NetworkDriverBuilderError { + /// The unsafe block signer is not set. + #[error("unsafe block signer not set")] + UnsafeBlockSignerNotSet, + /// The chain ID is not set. + #[error("chain ID not set")] + ChainIdNotSet, + /// The gossip address is not set. + #[error("gossip_addr address not set")] + GossipAddrNotSet, + /// A behaviour error. + #[error("behaviour error: {0}")] + BehaviourError(#[from] BehaviourError), + /// A config builder error. + #[error("config builder error")] + ConfigBuilderError, + /// A TCP error. + #[error("TCP error")] + TcpError, + /// An error when setting the behaviour on the swarm builder. + #[error("error setting behaviour on swarm builder")] + WithBehaviourError, + /// A discovery builder error. + #[error("discovery builder error: {0}")] + DiscoveryBuilderError(#[from] DiscoveryBuilderError), +} + +/// Constructs a [NetworkDriver] for Optimism's consensus-layer. +#[derive(Default)] +pub struct NetworkDriverBuilder { + /// The chain ID of the network. + pub chain_id: Option, + /// The unsafe block signer. + pub unsafe_block_signer: Option
, + /// The socket address that the gossip service is listening on. + pub gossip_addr: Option, + /// The listen config that the discovery service is listening on. + pub discovery_addr: Option, + /// The [GossipConfig] constructs the config for `gossipsub`. + pub gossip_config: Option, + /// The interval to discovery random nodes. + pub interval: Option, + /// The [Config] constructs the config for `discv5`. + pub discovery_config: Option, + /// The [Keypair] for the node. + pub keypair: Option, + /// The [TcpConfig] for the swarm. + pub tcp_config: Option, + /// The [NoiseConfig] for the swarm. + pub noise_config: Option, + /// The [YamuxConfig] for the swarm. + pub yamux_config: Option, + /// The idle connection timeout. + pub timeout: Option, +} + +impl NetworkDriverBuilder { + /// Creates a new [NetworkDriverBuilder]. + pub fn new() -> Self { + Self::default() + } + + /// Specifies the chain ID of the network. + pub fn with_chain_id(&mut self, chain_id: u64) -> &mut Self { + self.chain_id = Some(chain_id); + self + } + + /// Specifies the unsafe block signer. + pub fn with_unsafe_block_signer(&mut self, unsafe_block_signer: Address) -> &mut Self { + self.unsafe_block_signer = Some(unsafe_block_signer); + self + } + + /// Specifies the interval to discovery random nodes. + pub fn with_interval(&mut self, interval: Duration) -> &mut Self { + self.interval = Some(interval); + self + } + + /// Specifies the socket address that the gossip service is listening on. + pub fn with_gossip_addr(&mut self, socket: SocketAddr) -> &mut Self { + self.gossip_addr = Some(socket); + self + } + + /// Specifies the listen config that the discovery service is listening on. + pub fn with_discovery_addr(&mut self, listen_config: ListenConfig) -> &mut Self { + self.discovery_addr = Some(listen_config); + self + } + + /// Specifies the keypair for the node. + pub fn with_keypair(&mut self, keypair: Keypair) -> &mut Self { + self.keypair = Some(keypair); + self + } + + /// Specifies the [TcpConfig] for the swarm. + pub fn with_tcp_config(&mut self, tcp_config: TcpConfig) -> &mut Self { + self.tcp_config = Some(tcp_config); + self + } + + /// Specifies the [NoiseConfig] for the swarm. + pub fn with_noise_config(&mut self, noise_config: NoiseConfig) -> &mut Self { + self.noise_config = Some(noise_config); + self + } + + /// Specifies the [YamuxConfig] for the swarm. + pub fn with_yamux_config(&mut self, yamux_config: YamuxConfig) -> &mut Self { + self.yamux_config = Some(yamux_config); + self + } + + /// Set the swarm's idle connection timeout. + pub fn with_idle_connection_timeout(&mut self, timeout: Duration) -> &mut Self { + self.timeout = Some(timeout); + self + } + + /// Specifies the [GossipConfig] for the `gossipsub` configuration. + /// + /// If not set, the [NetworkDriverBuilder] will use the default gossipsub + /// configuration defined in [config::default_config]. These defaults can + /// be extended by using the [config::default_config_builder] method to + /// build a custom [GossipConfig]. + /// + /// ## Example + /// + /// ```rust,ignore + /// use kona_net::gossip::config; + /// use kona_net::NetworkDriverBuilder; + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let chain_id = 10; + /// let signer = Address::random(); + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + /// + /// // Let's say we want to enable flood publishing and use all other default settings. + /// let cfg = config::default_config_builder().flood_publish(true).build().unwrap(); + /// let mut builder = NetworkDriverBuilder::new() + /// .with_unsafe_block_signer(signer) + /// .with_chain_id(chain_id) + /// .with_gossip_addr(socket) + /// .with_gossip_config(cfg); + /// .build() + /// .unwrap(); + /// ``` + pub fn with_gossip_config(&mut self, cfg: GossipConfig) -> &mut Self { + self.gossip_config = Some(cfg); + self + } + + /// Specifies the [Config] for the `discv5` configuration. + /// + /// If not set, the [NetworkDriverBuilder] will fall back to use the [ListenConfig] + /// to construct [Config]. These defaults can be extended by using the + /// [discv5::ConfigBuilder::new] method to build a custom [Config]. + /// + /// ## Example + /// + /// ```rust + /// use alloy_primitives::{address, Address}; + /// use discv5::{ConfigBuilder, ListenConfig}; + /// use kona_net::builder::NetworkDriverBuilder; + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let id = 10; + /// let signer = Address::random(); + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + /// let discovery_config = + /// ConfigBuilder::new(ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9098)) + /// .build(); + /// let driver = NetworkDriverBuilder::new() + /// .with_unsafe_block_signer(signer) + /// .with_chain_id(id) + /// .with_gossip_addr(socket) + /// .with_discovery_config(discovery_config) + /// .build() + /// .unwrap(); + /// ``` + pub fn with_discovery_config(&mut self, cfg: Config) -> &mut Self { + self.discovery_config = Some(cfg); + self + } + + /// Builds the [NetworkDriver]. + /// + /// ## Errors + /// + /// Returns an error if any of the following required fields are not set: + /// - [NetworkDriverBuilder::unsafe_block_signer] + /// - [NetworkDriverBuilder::chain_id] + /// - [NetworkDriverBuilder::gossip_addr] + /// + /// If explicitly set, the following fields are used for discovery address, otherwise the gossip + /// address is used: + /// - [NetworkDriverBuilder::discovery_addr] + /// + /// Set these fields using the respective methods on the [NetworkDriverBuilder] + /// before calling this method. + /// + /// ## Example + /// + /// ```rust,ignore + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// use kona_net::NetworkDriverBuilder; + /// + /// let chain_id = 10; + /// let signer = Address::random(); + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + /// let driver = NetworkDriverBuilder::new() + /// .with_unsafe_block_signer(signer) + /// .with_chain_id(chain_id) + /// .with_gossip_addr(socket) + /// .build() + /// .unwrap(); + /// + /// Or if you want to use a different discovery address: + /// + /// let chain_id = 10; + /// let signer = Address::random(); + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + /// let listen_config = ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9999); + /// let driver = NetworkDriverBuilder::new() + /// .with_unsafe_block_signer(signer) + /// .with_chain_id(chain_id) + /// .with_gossip_addr(socket) + /// .with_discovery_addr(listen_config) + /// .build() + /// .unwrap(); + /// ``` + pub fn build(&mut self) -> Result { + // Build the config for gossipsub. + let config = match self.gossip_config.take() { + Some(cfg) => cfg, + None => config::default_config() + .map_err(|_| NetworkDriverBuilderError::ConfigBuilderError)?, + }; + let unsafe_block_signer = + self.unsafe_block_signer.ok_or(NetworkDriverBuilderError::UnsafeBlockSignerNotSet)?; + let chain_id = self.chain_id.ok_or(NetworkDriverBuilderError::ChainIdNotSet)?; + + // Create the block handler. + let (unsafe_block_signer_sender, unsafe_block_signer_recv) = channel(unsafe_block_signer); + let (handler, unsafe_block_recv) = BlockHandler::new(chain_id, unsafe_block_signer_recv); + + // Construct the gossipsub behaviour. + let behaviour = Behaviour::new(config, &[Box::new(handler.clone())])?; + + // Build the swarm. + let timeout = self.timeout.take().unwrap_or(Duration::from_secs(60)); + let noise_config = self.noise_config.take(); + let keypair = self.keypair.take().unwrap_or(Keypair::generate_secp256k1()); + let swarm = SwarmBuilder::with_existing_identity(keypair) + .with_tokio() + .with_tcp( + self.tcp_config.take().unwrap_or_default(), + |i: &Keypair| match noise_config { + Some(cfg) => Ok(cfg), + None => NoiseConfig::new(i), + }, + || self.yamux_config.take().unwrap_or_default(), + ) + .map_err(|_| NetworkDriverBuilderError::TcpError)? + .with_behaviour(|_| behaviour) + .map_err(|_| NetworkDriverBuilderError::WithBehaviourError)? + .with_swarm_config(|c| c.with_idle_connection_timeout(timeout)) + .build(); + + let gossip_addr = + self.gossip_addr.take().ok_or(NetworkDriverBuilderError::GossipAddrNotSet)?; + let mut multiaddr = Multiaddr::empty(); + match gossip_addr.ip() { + IpAddr::V4(ip) => multiaddr.push(Protocol::Ip4(ip)), + IpAddr::V6(ip) => multiaddr.push(Protocol::Ip6(ip)), + } + multiaddr.push(Protocol::Tcp(gossip_addr.port())); + let gossip = GossipDriver::new(swarm, multiaddr, handler.clone()); + + // Build the discovery service + let mut discovery_builder = + DiscoveryBuilder::new().with_address(gossip_addr).with_chain_id(chain_id); + + if let Some(discovery_addr) = self.discovery_addr.take() { + discovery_builder = discovery_builder.with_listen_config(discovery_addr); + } + + if let Some(discovery_config) = self.discovery_config.take() { + discovery_builder = discovery_builder.with_discovery_config(discovery_config); + } + + let mut discovery = discovery_builder.build()?; + discovery.interval = self.interval.unwrap_or(Duration::from_secs(10)); + + Ok(NetworkDriver { + discovery, + gossip, + unsafe_block_recv: Some(unsafe_block_recv), + unsafe_block_signer_sender: Some(unsafe_block_signer_sender), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use discv5::ConfigBuilder; + use libp2p::gossipsub::IdentTopic; + use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + + #[test] + fn test_build_missing_unsafe_block_signer() { + let mut builder = NetworkDriverBuilder::new(); + let Err(err) = builder.build() else { + panic!("expected error when building NetworkDriver without unsafe block signer"); + }; + assert_eq!(err, NetworkDriverBuilderError::UnsafeBlockSignerNotSet); + } + + #[test] + fn test_build_missing_chain_id() { + let mut builder = NetworkDriverBuilder::new(); + let Err(err) = builder.with_unsafe_block_signer(Address::random()).build() else { + panic!("expected error when building NetworkDriver without chain id"); + }; + assert_eq!(err, NetworkDriverBuilderError::ChainIdNotSet); + } + + #[test] + fn test_build_missing_socket() { + let mut builder = NetworkDriverBuilder::new(); + let Err(err) = builder.with_unsafe_block_signer(Address::random()).with_chain_id(1).build() + else { + panic!("expected error when building NetworkDriver without socket"); + }; + assert_eq!(err, NetworkDriverBuilderError::GossipAddrNotSet); + } + + #[test] + fn test_build_custom_gossip_config() { + let id = 10; + let signer = Address::random(); + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + let cfg = config::default_config_builder().flood_publish(true).build().unwrap(); + let driver = NetworkDriverBuilder::new() + .with_unsafe_block_signer(signer) + .with_chain_id(id) + .with_gossip_addr(socket) + .with_gossip_config(cfg) + .build() + .unwrap(); + let mut multiaddr = Multiaddr::empty(); + match socket.ip() { + IpAddr::V4(ip) => multiaddr.push(Protocol::Ip4(ip)), + IpAddr::V6(ip) => multiaddr.push(Protocol::Ip6(ip)), + } + multiaddr.push(Protocol::Tcp(socket.port())); + + // Driver Assertions + assert_eq!(driver.gossip.addr, multiaddr); + assert_eq!(driver.discovery.chain_id, id); + + // Block Handler Assertions + assert_eq!(driver.gossip.handler.chain_id, id); + let v1 = IdentTopic::new(format!("/optimism/{}/0/blocks", id)); + assert_eq!(driver.gossip.handler.blocks_v1_topic.hash(), v1.hash()); + let v2 = IdentTopic::new(format!("/optimism/{}/1/blocks", id)); + assert_eq!(driver.gossip.handler.blocks_v2_topic.hash(), v2.hash()); + let v3 = IdentTopic::new(format!("/optimism/{}/2/blocks", id)); + assert_eq!(driver.gossip.handler.blocks_v3_topic.hash(), v3.hash()); + } + + #[test] + fn test_build_default_network_driver() { + let id = 10; + let signer = Address::random(); + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + let driver = NetworkDriverBuilder::new() + .with_unsafe_block_signer(signer) + .with_chain_id(id) + .with_gossip_addr(socket) + .build() + .unwrap(); + let mut multiaddr = Multiaddr::empty(); + match socket.ip() { + IpAddr::V4(ip) => multiaddr.push(Protocol::Ip4(ip)), + IpAddr::V6(ip) => multiaddr.push(Protocol::Ip6(ip)), + } + multiaddr.push(Protocol::Tcp(socket.port())); + + // Driver Assertions + assert_eq!(driver.gossip.addr, multiaddr); + assert_eq!(driver.discovery.chain_id, id); + assert_eq!(driver.discovery.disc.local_enr().tcp4().unwrap(), 9099); + + // Block Handler Assertions + assert_eq!(driver.gossip.handler.chain_id, id); + let v1 = IdentTopic::new(format!("/optimism/{}/0/blocks", id)); + assert_eq!(driver.gossip.handler.blocks_v1_topic.hash(), v1.hash()); + let v2 = IdentTopic::new(format!("/optimism/{}/1/blocks", id)); + assert_eq!(driver.gossip.handler.blocks_v2_topic.hash(), v2.hash()); + let v3 = IdentTopic::new(format!("/optimism/{}/2/blocks", id)); + assert_eq!(driver.gossip.handler.blocks_v3_topic.hash(), v3.hash()); + } + + #[test] + fn test_build_network_driver_with_discovery_addr() { + let id = 10; + let signer = Address::random(); + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + let discovery_addr = ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9098); + let driver = NetworkDriverBuilder::new() + .with_unsafe_block_signer(signer) + .with_chain_id(id) + .with_gossip_addr(socket) + .with_discovery_addr(discovery_addr) + .build() + .unwrap(); + + assert_eq!(driver.discovery.disc.local_enr().tcp4().unwrap(), 9098); + } + + #[test] + fn test_build_network_driver_with_discovery_config() { + let id = 10; + let signer = Address::random(); + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + let discovery_config = + ConfigBuilder::new(ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9098)) + .build(); + let driver = NetworkDriverBuilder::new() + .with_unsafe_block_signer(signer) + .with_chain_id(id) + .with_gossip_addr(socket) + .with_discovery_config(discovery_config) + .build() + .unwrap(); + + assert_eq!(driver.discovery.disc.local_enr().tcp4().unwrap(), 9098); + } + + #[test] + fn test_build_network_driver_with_discovery_config_and_listen_config() { + let id = 10; + let signer = Address::random(); + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + let discovery_config = + ConfigBuilder::new(ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9098)) + .build(); + let discovery_addr = ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9097); + let driver = NetworkDriverBuilder::new() + .with_unsafe_block_signer(signer) + .with_chain_id(id) + .with_gossip_addr(socket) + .with_discovery_addr(discovery_addr) + .with_discovery_config(discovery_config) + .build() + .unwrap(); + + assert_eq!(driver.discovery.disc.local_enr().tcp4().unwrap(), 9097); + } +} diff --git a/crates/services/net/src/discovery/bootnodes.rs b/crates/services/net/src/discovery/bootnodes.rs new file mode 100644 index 000000000..6c29020db --- /dev/null +++ b/crates/services/net/src/discovery/bootnodes.rs @@ -0,0 +1,35 @@ +//! Bootnodes for consensus network discovery. + +use discv5::enr::{CombinedKey, Enr}; +use lazy_static::lazy_static; +use std::str::FromStr; + +lazy_static! { + /// Default bootnodes to use. + pub static ref BOOTNODES: Vec> = [ + // Optimism Mainnet Bootnodes + Enr::from_str("enr:-J64QBbwPjPLZ6IOOToOLsSjtFUjjzN66qmBZdUexpO32Klrc458Q24kbty2PdRaLacHM5z-cZQr8mjeQu3pik6jPSOGAYYFIqBfgmlkgnY0gmlwhDaRWFWHb3BzdGFja4SzlAUAiXNlY3AyNTZrMaECmeSnJh7zjKrDSPoNMGXoopeDF4hhpj5I0OsQUUt4u8uDdGNwgiQGg3VkcIIkBg").unwrap(), + Enr::from_str("enr:-J64QAlTCDa188Hl1OGv5_2Kj2nWCsvxMVc_rEnLtw7RPFbOfqUOV6khXT_PH6cC603I2ynY31rSQ8sI9gLeJbfFGaWGAYYFIrpdgmlkgnY0gmlwhANWgzCHb3BzdGFja4SzlAUAiXNlY3AyNTZrMaECkySjcg-2v0uWAsFsZZu43qNHppGr2D5F913Qqs5jDCGDdGNwgiQGg3VkcIIkBg").unwrap(), + Enr::from_str("enr:-J24QGEzN4mJgLWNTUNwj7riVJ2ZjRLenOFccl2dbRFxHHOCCZx8SXWzgf-sLzrGs6QgqSFCvGXVgGPBkRkfOWlT1-iGAYe6Cu93gmlkgnY0gmlwhCJBEUSHb3BzdGFja4OkAwCJc2VjcDI1NmsxoQLuYIwaYOHg3CUQhCkS-RsSHmUd1b_x93-9yQ5ItS6udIN0Y3CCIyuDdWRwgiMr").unwrap(), + + // Base Mainnet Bootnodes + Enr::from_str("enr:-J24QNz9lbrKbN4iSmmjtnr7SjUMk4zB7f1krHZcTZx-JRKZd0kA2gjufUROD6T3sOWDVDnFJRvqBBo62zuF-hYCohOGAYiOoEyEgmlkgnY0gmlwhAPniryHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQKNVFlCxh_B-716tTs-h1vMzZkSs1FTu_OYTNjgufplG4N0Y3CCJAaDdWRwgiQG").unwrap(), + Enr::from_str("enr:-J24QH-f1wt99sfpHy4c0QJM-NfmsIfmlLAMMcgZCUEgKG_BBYFc6FwYgaMJMQN5dsRBJApIok0jFn-9CS842lGpLmqGAYiOoDRAgmlkgnY0gmlwhLhIgb2Hb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJ9FTIv8B9myn1MWaC_2lJ-sMoeCDkusCsk4BYHjjCq04N0Y3CCJAaDdWRwgiQG").unwrap(), + Enr::from_str("enr:-J24QDXyyxvQYsd0yfsN0cRr1lZ1N11zGTplMNlW4xNEc7LkPXh0NAJ9iSOVdRO95GPYAIc6xmyoCCG6_0JxdL3a0zaGAYiOoAjFgmlkgnY0gmlwhAPckbGHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJwoS7tzwxqXSyFL7g0JM-KWVbgvjfB8JA__T7yY_cYboN0Y3CCJAaDdWRwgiQG").unwrap(), + Enr::from_str("enr:-J24QHmGyBwUZXIcsGYMaUqGGSl4CFdx9Tozu-vQCn5bHIQbR7On7dZbU61vYvfrJr30t0iahSqhc64J46MnUO2JvQaGAYiOoCKKgmlkgnY0gmlwhAPnCzSHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQINc4fSijfbNIiGhcgvwjsjxVFJHUstK9L1T8OTKUjgloN0Y3CCJAaDdWRwgiQG").unwrap(), + Enr::from_str("enr:-J24QG3ypT4xSu0gjb5PABCmVxZqBjVw9ca7pvsI8jl4KATYAnxBmfkaIuEqy9sKvDHKuNCsy57WwK9wTt2aQgcaDDyGAYiOoGAXgmlkgnY0gmlwhDbGmZaHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQIeAK_--tcLEiu7HvoUlbV52MspE0uCocsx1f_rYvRenIN0Y3CCJAaDdWRwgiQG").unwrap(), + + // Conduit Bootnode + // discv5::enr::NodeId::from("enode://9d7a3efefe442351217e73b3a593bcb8efffb55b4807699972145324eab5e6b382152f8d24f6301baebbfb5ecd4127bd3faab2842c04cd432bdf50ba092f6645@34.65.109.126:30305"), + ].to_vec(); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bootnodes() { + assert_eq!(BOOTNODES.len(), 8); + } +} diff --git a/crates/services/net/src/discovery/builder.rs b/crates/services/net/src/discovery/builder.rs new file mode 100644 index 000000000..117179464 --- /dev/null +++ b/crates/services/net/src/discovery/builder.rs @@ -0,0 +1,117 @@ +//! Contains a builder for the discovery service. + +use crate::{discovery::driver::DiscoveryDriver, types::enr::OpStackEnr}; +use discv5::{ + enr::{CombinedKey, Enr}, + Config, ConfigBuilder, Discv5, ListenConfig, +}; +use std::net::SocketAddr; + +use crate::types::enr::OP_CL_KEY; + +/// An error that can occur when building the discovery service. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum DiscoveryBuilderError { + /// The chain ID is not set. + #[error("chain ID not set")] + ChainIdNotSet, + /// The listen config is not set. + #[error("listen config not set")] + ListenConfigNotSet, + /// Could not create the discovery service. + #[error("could not create discovery service")] + Discv5CreationFailed, + /// Failed to build the ENR. + #[error("failed to build ENR")] + EnrBuildFailed, +} + +/// Discovery service builder. +#[derive(Debug, Default, Clone)] +pub struct DiscoveryBuilder { + /// The discovery service address. + address: Option, + /// The chain ID of the network. + chain_id: Option, + /// The listen config for the discovery service. + listen_config: Option, + + /// The discovery config for the discovery service. + discovery_config: Option, +} + +impl DiscoveryBuilder { + /// Creates a new discovery builder. + pub fn new() -> Self { + Self::default() + } + + /// Sets the discovery service address. + pub fn with_address(mut self, address: SocketAddr) -> Self { + self.address = Some(address); + self + } + + /// Sets the chain ID of the network. + pub fn with_chain_id(mut self, chain_id: u64) -> Self { + self.chain_id = Some(chain_id); + self + } + + /// Sets the listen config for the discovery service. + pub fn with_listen_config(mut self, listen_config: ListenConfig) -> Self { + self.listen_config = Some(listen_config); + self + } + + /// Sets the discovery config for the discovery service. + pub fn with_discovery_config(mut self, config: Config) -> Self { + self.discovery_config = Some(config); + self + } + + /// Builds a [DiscoveryDriver]. + pub fn build(&mut self) -> Result { + let chain_id = self.chain_id.ok_or(DiscoveryBuilderError::ChainIdNotSet)?; + let opstack = OpStackEnr::new(chain_id, 0); + let mut opstack_data = Vec::new(); + use alloy_rlp::Encodable; + opstack.encode(&mut opstack_data); + + let config = if let Some(mut discovery_config) = self.discovery_config.take() { + if let Some(listen_config) = self.listen_config.take() { + discovery_config.listen_config = listen_config; + } + Ok::(discovery_config) + } else { + let listen_config = self + .listen_config + .take() + .or_else(|| self.address.map(ListenConfig::from)) + .ok_or(DiscoveryBuilderError::ListenConfigNotSet)?; + Ok(ConfigBuilder::new(listen_config).build()) + }?; + + let key = CombinedKey::generate_secp256k1(); + let mut enr_builder = Enr::builder(); + enr_builder.add_value_rlp(OP_CL_KEY, opstack_data.into()); + match config.listen_config { + ListenConfig::Ipv4 { ip, port } => { + enr_builder.ip4(ip).tcp4(port); + } + ListenConfig::Ipv6 { ip, port } => { + enr_builder.ip6(ip).tcp6(port); + } + ListenConfig::DualStack { ipv4, ipv4_port, ipv6, ipv6_port } => { + enr_builder.ip4(ipv4).tcp4(ipv4_port); + enr_builder.ip6(ipv6).tcp6(ipv6_port); + } + } + let enr = enr_builder.build(&key).map_err(|_| DiscoveryBuilderError::EnrBuildFailed)?; + + let disc = Discv5::new(enr, key, config) + .map_err(|_| DiscoveryBuilderError::Discv5CreationFailed)?; + + Ok(DiscoveryDriver::new(disc, chain_id)) + } +} diff --git a/crates/services/net/src/discovery/driver.rs b/crates/services/net/src/discovery/driver.rs new file mode 100644 index 000000000..149e77f4b --- /dev/null +++ b/crates/services/net/src/discovery/driver.rs @@ -0,0 +1,118 @@ +//! Discovery Module. + +use std::time::Duration; +use tokio::{ + sync::mpsc::{channel, Receiver}, + time::sleep, +}; +use tracing::{info, warn}; + +use discv5::{enr::NodeId, Discv5}; + +use crate::{ + discovery::{bootnodes::BOOTNODES, builder::DiscoveryBuilder}, + types::{enr::OpStackEnr, peer::Peer}, +}; + +/// The number of peers to buffer in the channel. +const DISCOVERY_PEER_CHANNEL_SIZE: usize = 256; + +/// The discovery driver handles running the discovery service. +pub struct DiscoveryDriver { + /// The [Discv5] discovery service. + pub disc: Discv5, + /// The chain ID of the network. + pub chain_id: u64, + /// The interval to discovery random nodes. + pub interval: Duration, +} + +impl DiscoveryDriver { + /// Returns a new [DiscoveryBuilder] instance. + pub fn builder() -> DiscoveryBuilder { + DiscoveryBuilder::new() + } + + /// Instantiates a new [DiscoveryDriver]. + pub fn new(disc: Discv5, chain_id: u64) -> Self { + Self { disc, chain_id, interval: Duration::from_secs(10) } + } + + /// Spawns a new [Discv5] discovery service in a new tokio task. + /// + /// Returns a [Receiver] to receive [Peer] structs. + /// + /// ## Errors + /// + /// Returns an error if the address or chain ID is not set + /// on the [crate::discovery::builder::DiscoveryBuilder]. + /// + /// ## Example + /// + /// ```no_run + /// use kona_net::discovery::builder::DiscoveryBuilder; + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// #[tokio::main] + /// async fn main() { + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); + /// let mut discovery = DiscoveryBuilder::new() + /// .with_address(socket) + /// .with_chain_id(10) // OP Mainnet chain id + /// .build() + /// .expect("Failed to build discovery service"); + /// let mut peer_recv = discovery.start(); + /// + /// loop { + /// if let Some(peer) = peer_recv.recv().await { + /// println!("Received peer: {:?}", peer); + /// } + /// } + /// } + /// ``` + pub fn start(mut self) -> Receiver { + // Clone the bootnodes since the spawned thread takes mutable ownership. + let bootnodes = BOOTNODES.clone(); + + // Create a multi-producer, single-consumer (mpsc) channel to receive + // peers bounded by `DISCOVERY_PEER_CHANNEL_SIZE`. + let (sender, recv) = channel::(DISCOVERY_PEER_CHANNEL_SIZE); + + tokio::spawn(async move { + bootnodes.into_iter().for_each(|enr| _ = self.disc.add_enr(enr)); + loop { + if let Err(e) = self.disc.start().await { + warn!("Failed to start discovery service: {:?}", e); + sleep(Duration::from_secs(2)).await; + continue; + } + break; + } + + info!("Started peer discovery"); + + loop { + let target = NodeId::random(); + match self.disc.find_node(target).await { + Ok(nodes) => { + let peers = nodes + .iter() + .filter(|node| OpStackEnr::is_valid_node(node, self.chain_id)) + .flat_map(Peer::try_from); + + for peer in peers { + _ = sender.send(peer).await; + } + } + Err(err) => { + warn!("discovery error: {:?}", err); + } + } + + sleep(self.interval).await; + } + }); + + recv + } +} diff --git a/crates/services/net/src/discovery/mod.rs b/crates/services/net/src/discovery/mod.rs new file mode 100644 index 000000000..633c76bb5 --- /dev/null +++ b/crates/services/net/src/discovery/mod.rs @@ -0,0 +1,5 @@ +//! Discovery Module for Optimism + +pub mod bootnodes; +pub mod builder; +pub mod driver; diff --git a/crates/services/net/src/driver.rs b/crates/services/net/src/driver.rs new file mode 100644 index 000000000..d216cb5b2 --- /dev/null +++ b/crates/services/net/src/driver.rs @@ -0,0 +1,69 @@ +//! Driver for network services. + +use std::sync::mpsc::Receiver; + +use alloy_primitives::Address; +use alloy_rpc_types_engine::ExecutionPayload; +use libp2p::TransportError; +use tokio::{select, sync::watch}; + +use crate::{ + builder::NetworkDriverBuilder, discovery::driver::DiscoveryDriver, gossip::driver::GossipDriver, +}; + +/// NetworkDriver +/// +/// Contains the logic to run Optimism's consensus-layer networking stack. +/// There are two core services that are run by the driver: +/// - Block gossip through Gossipsub. +/// - Peer discovery with `discv5`. +pub struct NetworkDriver { + /// Channel to receive unsafe blocks. + pub(crate) unsafe_block_recv: Option>, + /// Channel to send unsafe signer updates. + pub(crate) unsafe_block_signer_sender: Option>, + /// The swarm instance. + pub gossip: GossipDriver, + /// The discovery service driver. + pub discovery: DiscoveryDriver, +} + +impl NetworkDriver { + /// Returns a new [NetworkDriverBuilder]. + pub fn builder() -> NetworkDriverBuilder { + NetworkDriverBuilder::new() + } + + /// Take the unsafe block receiver. + pub fn take_unsafe_block_recv(&mut self) -> Option> { + self.unsafe_block_recv.take() + } + + /// Take the unsafe block signer sender. + pub fn take_unsafe_block_signer_sender(&mut self) -> Option> { + self.unsafe_block_signer_sender.take() + } + + /// Starts the Discv5 peer discovery & libp2p services + /// and continually listens for new peers and messages to handle + pub fn start(mut self) -> Result<(), TransportError> { + let mut peer_recv = self.discovery.start(); + self.gossip.listen()?; + tokio::spawn(async move { + loop { + select! { + peer = peer_recv.recv() => { + self.gossip.dial_opt(peer.clone()).await; + tracing::info!("Received peer: {:?} | Connected peers: {:?}", peer, self.gossip.connected_peers()); + }, + event = self.gossip.select_next_some() => { + tracing::debug!("Received event: {:?}", event); + self.gossip.handle_event(event); + }, + } + } + }); + + Ok(()) + } +} diff --git a/crates/services/net/src/gossip/behaviour.rs b/crates/services/net/src/gossip/behaviour.rs new file mode 100644 index 000000000..210a6f491 --- /dev/null +++ b/crates/services/net/src/gossip/behaviour.rs @@ -0,0 +1,91 @@ +//! Network Behaviour Module. + +use libp2p::{ + gossipsub::{Config, IdentTopic, MessageAuthenticity}, + swarm::NetworkBehaviour, +}; + +use super::{event::Event, handler::Handler}; + +/// An error that can occur when creating a [Behaviour]. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum BehaviourError { + /// The gossipsub behaviour creation failed. + #[error("gossipsub behaviour creation failed")] + GossipsubCreationFailed, + /// Subscription failed. + #[error("subscription failed")] + SubscriptionFailed, +} + +/// Specifies the [NetworkBehaviour] of the node +#[derive(NetworkBehaviour)] +#[behaviour(out_event = "Event")] +pub struct Behaviour { + /// Responds to inbound pings and send outbound pings. + pub ping: libp2p::ping::Behaviour, + /// Enables gossipsub as the routing layer. + pub gossipsub: libp2p::gossipsub::Behaviour, +} + +impl Behaviour { + /// Configures the swarm behaviors, subscribes to the gossip topics, and returns a new + /// [Behaviour]. + pub fn new(cfg: Config, handlers: &[Box]) -> Result { + let ping = libp2p::ping::Behaviour::default(); + + let mut gossipsub = libp2p::gossipsub::Behaviour::new(MessageAuthenticity::Anonymous, cfg) + .map_err(|_| BehaviourError::GossipsubCreationFailed)?; + + handlers + .iter() + .flat_map(|handler| { + handler + .topics() + .iter() + .map(|topic| { + let topic = IdentTopic::new(topic.to_string()); + gossipsub.subscribe(&topic).map_err(|_| BehaviourError::SubscriptionFailed) + }) + .collect::>() + }) + .collect::, BehaviourError>>()?; + + Ok(Self { ping, gossipsub }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::gossip::{config, handler::BlockHandler}; + use alloy_primitives::Address; + use libp2p::gossipsub::{IdentTopic, TopicHash}; + + fn zero_topics() -> Vec { + vec![ + IdentTopic::new("/optimism/0/0/blocks").hash(), + IdentTopic::new("/optimism/0/1/blocks").hash(), + IdentTopic::new("/optimism/0/2/blocks").hash(), + ] + } + + #[test] + fn test_behaviour_no_handlers() { + let cfg = config::default_config_builder().build().expect("Failed to build default config"); + let handlers = vec![]; + let _ = Behaviour::new(cfg, &handlers).unwrap(); + } + + #[test] + fn test_behaviour_with_handlers() { + let cfg = config::default_config_builder().build().expect("Failed to build default config"); + let (_, recv) = tokio::sync::watch::channel(Address::default()); + let (block_handler, _) = BlockHandler::new(0, recv); + let handlers: Vec> = vec![Box::new(block_handler)]; + let behaviour = Behaviour::new(cfg, &handlers).unwrap(); + let mut topics = behaviour.gossipsub.topics().cloned().collect::>(); + topics.sort(); + assert_eq!(topics, zero_topics()); + } +} diff --git a/crates/services/net/src/gossip/config.rs b/crates/services/net/src/gossip/config.rs new file mode 100644 index 000000000..01aad8e64 --- /dev/null +++ b/crates/services/net/src/gossip/config.rs @@ -0,0 +1,118 @@ +//! Gossipsub Configuration + +use lazy_static::lazy_static; +use libp2p::gossipsub::{Config, ConfigBuilder, ConfigBuilderError, Message, MessageId}; +use openssl::sha::sha256; +use snap::raw::Decoder; +use std::time::Duration; + +//////////////////////////////////////////////////////////////////////////////////////////////// +// GossipSub Constants +//////////////////////////////////////////////////////////////////////////////////////////////// + +/// The maximum gossip size. +/// Limits the total size of gossip RPC containers as well as decompressed individual messages. +pub const MAX_GOSSIP_SIZE: usize = 10 * (1 << 20); + +/// The minimum gossip size. +/// Used to make sure that there is at least some data to validate the signature against. +pub const MIN_GOSSIP_SIZE: usize = 66; + +/// The maximum outbound queue. +pub const MAX_OUTBOUND_QUEUE: usize = 256; + +/// The maximum validate queue. +pub const MAX_VALIDATE_QUEUE: usize = 256; + +/// The global validate throttle. +pub const GLOBAL_VALIDATE_THROTTLE: usize = 512; + +/// The default mesh D. +pub const DEFAULT_MESH_D: usize = 8; + +/// The default mesh D low. +pub const DEFAULT_MESH_DLO: usize = 6; + +/// The default mesh D high. +pub const DEFAULT_MESH_DHI: usize = 12; + +/// The default mesh D lazy. +pub const DEFAULT_MESH_DLAZY: usize = 6; + +//////////////////////////////////////////////////////////////////////////////////////////////// +// Duration Constants +//////////////////////////////////////////////////////////////////////////////////////////////// + +lazy_static! { + /// The gossip heartbeat. + pub static ref GOSSIP_HEARTBEAT: Duration = Duration::from_millis(500); + + /// The seen messages TTL. + /// Limits the duration that message IDs are remembered for gossip deduplication purposes. + pub static ref SEEN_MESSAGES_TTL: Duration = 130 * *GOSSIP_HEARTBEAT; + + /// The pper score inspect frequency. + /// The frequency at which peer scores are inspected. + pub static ref PEER_SCORE_INSPECT_FREQUENCY: Duration = 15 * Duration::from_secs(1); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// Config Building +//////////////////////////////////////////////////////////////////////////////////////////////// + +/// Builds the default gossipsub configuration. +/// +/// Notable defaults: +/// - flood_publish: false (call `.flood_publish(true)` on the [ConfigBuilder] to enable) +/// - backoff_slack: 1 +/// - heart beat interval: 1 second +/// - peer exchange is disabled +/// - maximum byte size for gossip messages: 2048 bytes +/// +/// # Returns +/// +/// A [`ConfigBuilder`] with the default gossipsub configuration already set. +/// Call `.build()` on the returned builder to get the final [libp2p::gossipsub::Config]. +pub fn default_config_builder() -> ConfigBuilder { + let mut builder = ConfigBuilder::default(); + builder + .mesh_n(DEFAULT_MESH_D) + .mesh_n_low(DEFAULT_MESH_DLO) + .mesh_n_high(DEFAULT_MESH_DHI) + .gossip_lazy(DEFAULT_MESH_DLAZY) + .heartbeat_interval(*GOSSIP_HEARTBEAT) + .fanout_ttl(Duration::from_secs(24)) + .history_length(12) + .history_gossip(3) + .duplicate_cache_time(Duration::from_secs(65)) + .validation_mode(libp2p::gossipsub::ValidationMode::None) + .validate_messages() + .message_id_fn(compute_message_id); + + builder +} + +/// Returns the default [Config] for gossipsub. +pub fn default_config() -> Result { + default_config_builder().build() +} + +/// Computes the [MessageId] of a `gossipsub` message. +fn compute_message_id(msg: &Message) -> MessageId { + let mut decoder = Decoder::new(); + let id = match decoder.decompress_vec(&msg.data) { + Ok(data) => { + let domain_valid_snappy: Vec = vec![0x1, 0x0, 0x0, 0x0]; + sha256([domain_valid_snappy.as_slice(), data.as_slice()].concat().as_slice())[..20] + .to_vec() + } + Err(_) => { + let domain_invalid_snappy: Vec = vec![0x0, 0x0, 0x0, 0x0]; + sha256([domain_invalid_snappy.as_slice(), msg.data.as_slice()].concat().as_slice()) + [..20] + .to_vec() + } + }; + + MessageId(id) +} diff --git a/crates/services/net/src/gossip/driver.rs b/crates/services/net/src/gossip/driver.rs new file mode 100644 index 000000000..31bf1df15 --- /dev/null +++ b/crates/services/net/src/gossip/driver.rs @@ -0,0 +1,92 @@ +//! Consensus-layer gossipsub driver for Optimism. + +use crate::gossip::{ + behaviour::Behaviour, + event::Event, + handler::{BlockHandler, Handler}, +}; +use futures::stream::StreamExt; +use libp2p::{ + swarm::{DialError, SwarmEvent}, + Multiaddr, Swarm, TransportError, +}; +use tracing::{debug, error, info}; + +/// A [libp2p::Swarm] instance with an associated address to listen on. +pub struct GossipDriver { + /// The [libp2p::Swarm] instance. + pub swarm: Swarm, + /// The address to listen on. + pub addr: Multiaddr, + /// Block handler. + pub handler: BlockHandler, +} + +impl GossipDriver { + /// Creates a new [GossipDriver] instance. + pub fn new(swarm: Swarm, addr: Multiaddr, handler: BlockHandler) -> Self { + Self { swarm, addr, handler } + } + + /// Listens on the address. + pub fn listen(&mut self) -> Result<(), TransportError> { + self.swarm.listen_on(self.addr.clone())?; + info!("Swarm listening on: {:?}", self.addr); + Ok(()) + } + + /// Returns a mutable reference to the Swarm's behaviour. + pub fn behaviour_mut(&mut self) -> &mut Behaviour { + self.swarm.behaviour_mut() + } + + /// Attempts to select the next event from the Swarm. + pub async fn select_next_some(&mut self) -> SwarmEvent { + self.swarm.select_next_some().await + } + + /// Returns the number of connected peers. + pub fn connected_peers(&self) -> usize { + self.swarm.connected_peers().count() + } + + /// Dials the given [`Option`]. + pub async fn dial_opt(&mut self, peer: Option>) { + let Some(addr) = peer else { + return; + }; + match self.dial(addr).await { + Ok(_) => info!("Dialed peer"), + Err(e) => error!("Failed to dial peer: {:?}", e), + } + } + + /// Dials the given [Multiaddr]. + pub async fn dial(&mut self, peer: impl Into) -> Result<(), DialError> { + let addr: Multiaddr = peer.into(); + self.swarm.dial(addr)?; + Ok(()) + } + + /// Handles the [`SwarmEvent`]. + pub fn handle_event(&mut self, event: SwarmEvent) { + if let SwarmEvent::Behaviour(Event::Gossipsub(libp2p::gossipsub::Event::Message { + propagation_source: src, + message_id: id, + message, + })) = event + { + debug!("Received message with topic: {}", message.topic); + if self.handler.topics().contains(&message.topic) { + debug!("Handling message with topic: {}", message.topic); + let status = self.handler.handle(message); + debug!("Reporting message validation result: {:?}", status); + _ = self + .swarm + .behaviour_mut() + .gossipsub + .report_message_validation_result(&id, &src, status); + } + } + } +} diff --git a/crates/services/net/src/gossip/event.rs b/crates/services/net/src/gossip/event.rs new file mode 100644 index 000000000..01751304a --- /dev/null +++ b/crates/services/net/src/gossip/event.rs @@ -0,0 +1,27 @@ +//! Event Handling Module. + +use libp2p::{gossipsub, ping}; + +/// The type of message received +#[derive(Debug)] +pub enum Event { + /// Represents a [ping::Event] + #[allow(dead_code)] + Ping(ping::Event), + /// Represents a [gossipsub::Event] + Gossipsub(gossipsub::Event), +} + +impl From for Event { + /// Converts [ping::Event] to [Event] + fn from(value: ping::Event) -> Self { + Event::Ping(value) + } +} + +impl From for Event { + /// Converts [gossipsub::Event] to [Event] + fn from(value: gossipsub::Event) -> Self { + Event::Gossipsub(value) + } +} diff --git a/crates/services/net/src/gossip/handler.rs b/crates/services/net/src/gossip/handler.rs new file mode 100644 index 000000000..60e80b868 --- /dev/null +++ b/crates/services/net/src/gossip/handler.rs @@ -0,0 +1,129 @@ +//! Block Handler + +use std::{ + sync::mpsc::{channel, Receiver, Sender}, + time::SystemTime, +}; + +use alloy_primitives::Address; +use alloy_rpc_types_engine::ExecutionPayload; +use libp2p::gossipsub::{IdentTopic, Message, MessageAcceptance, TopicHash}; +use op_alloy_rpc_types_engine::OpNetworkPayloadEnvelope; +use tokio::sync::watch; + +/// This trait defines the functionality required to process incoming messages +/// and determine their acceptance within the network. +/// +/// Implementors of this trait can specify how messages are handled and which +/// topics they are interested in. +pub trait Handler: Send { + /// Manages validation and further processing of messages + fn handle(&self, msg: Message) -> MessageAcceptance; + + /// Specifies which topics the handler is interested in + fn topics(&self) -> Vec; +} + +/// Responsible for managing blocks received via p2p gossip +#[derive(Debug, Clone)] +pub struct BlockHandler { + /// Chain ID of the L2 blockchain. Used to filter out gossip messages intended for other + /// blockchains. + pub chain_id: u64, + /// A channel sender to forward new blocks to other modules + pub block_sender: Sender, + /// A [Receiver] to monitor changes to the unsafe block signer. + pub unsafe_signer_recv: watch::Receiver
, + /// The libp2p topic for pre Canyon/Shangai blocks. + pub blocks_v1_topic: IdentTopic, + /// The libp2p topic for Canyon/Delta blocks. + pub blocks_v2_topic: IdentTopic, + /// The libp2p topic for Ecotone V3 blocks. + pub blocks_v3_topic: IdentTopic, +} + +impl Handler for BlockHandler { + /// Checks validity of a block received via p2p gossip, and sends to the block update channel if + /// valid. + fn handle(&self, msg: Message) -> MessageAcceptance { + tracing::debug!("received block"); + + let decoded = if msg.topic == self.blocks_v1_topic.hash() { + tracing::debug!("received v1 block"); + OpNetworkPayloadEnvelope::decode_v1(&msg.data) + } else if msg.topic == self.blocks_v2_topic.hash() { + tracing::debug!("received v2 block"); + OpNetworkPayloadEnvelope::decode_v2(&msg.data) + } else if msg.topic == self.blocks_v3_topic.hash() { + tracing::debug!("received v3 block"); + OpNetworkPayloadEnvelope::decode_v3(&msg.data) + } else { + return MessageAcceptance::Reject; + }; + + match decoded { + Ok(envelope) => { + if self.block_valid(&envelope) { + _ = self.block_sender.send(envelope.payload); + MessageAcceptance::Accept + } else { + tracing::warn!("invalid unsafe block"); + MessageAcceptance::Reject + } + } + Err(err) => { + tracing::warn!("unsafe block decode failed: {}", err); + MessageAcceptance::Reject + } + } + } + + /// The gossip topics accepted for new blocks + fn topics(&self) -> Vec { + vec![self.blocks_v1_topic.hash(), self.blocks_v2_topic.hash(), self.blocks_v3_topic.hash()] + } +} + +impl BlockHandler { + /// Creates a new [BlockHandler] and opens a channel + pub fn new( + chain_id: u64, + unsafe_recv: watch::Receiver
, + ) -> (Self, Receiver) { + let (sender, recv) = channel(); + + let handler = Self { + chain_id, + block_sender: sender, + unsafe_signer_recv: unsafe_recv, + blocks_v1_topic: IdentTopic::new(format!("/optimism/{}/0/blocks", chain_id)), + blocks_v2_topic: IdentTopic::new(format!("/optimism/{}/1/blocks", chain_id)), + blocks_v3_topic: IdentTopic::new(format!("/optimism/{}/2/blocks", chain_id)), + }; + + (handler, recv) + } + + /// Determines if a block is valid. + /// + /// True if the block is less than 1 minute old, and correctly signed by the unsafe block + /// signer. + fn block_valid(&self, envelope: &OpNetworkPayloadEnvelope) -> bool { + let current_timestamp = + SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + + let is_future = envelope.payload.timestamp() > current_timestamp + 5; + let is_past = envelope.payload.timestamp() < current_timestamp - 60; + let time_valid = !(is_future || is_past); + + let msg = envelope.payload_hash.signature_message(self.chain_id); + let block_signer = *self.unsafe_signer_recv.borrow(); + let Ok(msg_signer) = envelope.signature.recover_address_from_prehash(&msg) else { + tracing::warn!("Failed to recover address from message"); + return false; + }; + + let signer_valid = msg_signer == block_signer; + time_valid && signer_valid + } +} diff --git a/crates/services/net/src/gossip/mod.rs b/crates/services/net/src/gossip/mod.rs new file mode 100644 index 000000000..2257a6505 --- /dev/null +++ b/crates/services/net/src/gossip/mod.rs @@ -0,0 +1,7 @@ +//! Module containing consensus-layer gossipsub for optimism. + +pub mod behaviour; +pub mod config; +pub mod driver; +pub mod event; +pub mod handler; diff --git a/crates/services/net/src/lib.rs b/crates/services/net/src/lib.rs new file mode 100644 index 000000000..c681b76d6 --- /dev/null +++ b/crates/services/net/src/lib.rs @@ -0,0 +1,14 @@ +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico", + issue_tracker_base_url = "https://github.com/op-rs/kona/issues/" +)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +pub mod builder; +pub mod discovery; +pub mod driver; +pub mod gossip; +pub mod types; diff --git a/crates/services/net/src/types/enr.rs b/crates/services/net/src/types/enr.rs new file mode 100644 index 000000000..cb8bc8fb8 --- /dev/null +++ b/crates/services/net/src/types/enr.rs @@ -0,0 +1,118 @@ +//! Contains the Optimism consensus-layer ENR Type. + +use alloy_rlp::{Decodable, Encodable}; +use discv5::enr::{CombinedKey, Enr}; +use unsigned_varint::{decode, encode}; + +/// The ENR key literal string for the consensus layer. +pub const OP_CL_KEY: &str = "opstack"; + +/// The unique L2 network identifier +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] +pub struct OpStackEnr { + /// Chain ID + pub chain_id: u64, + /// The version. Always set to 0. + pub version: u64, +} + +impl OpStackEnr { + /// Instantiates a new Op Stack Enr. + pub fn new(chain_id: u64, version: u64) -> Self { + Self { chain_id, version } + } + + /// Returns `true` if a node [Enr] contains an `opstack` key and is on the same network. + pub fn is_valid_node(node: &Enr, chain_id: u64) -> bool { + node.get_raw_rlp(OP_CL_KEY) + .map(|mut opstack| { + OpStackEnr::decode(&mut opstack) + .map(|opstack| opstack.chain_id == chain_id && opstack.version == 0) + .unwrap_or_default() + }) + .unwrap_or_default() + } +} + +impl Encodable for OpStackEnr { + fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { + let mut chain_id_buf = encode::u128_buffer(); + let chain_id_slice = encode::u128(self.chain_id as u128, &mut chain_id_buf); + + let mut version_buf = encode::u128_buffer(); + let version_slice = encode::u128(self.version as u128, &mut version_buf); + + let opstack = [chain_id_slice, version_slice].concat(); + alloy_primitives::Bytes::from(opstack).encode(out); + } +} + +impl Decodable for OpStackEnr { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { + let bytes = alloy_primitives::Bytes::decode(buf)?; + let (chain_id, rest) = decode::u64(&bytes) + .map_err(|_| alloy_rlp::Error::Custom("could not decode chain id"))?; + let (version, _) = + decode::u64(rest).map_err(|_| alloy_rlp::Error::Custom("could not decode chain id"))?; + Ok(Self { chain_id, version }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::{bytes, Bytes}; + + #[test] + fn roundtrip_op_stack_enr() { + arbtest::arbtest(|u| { + let op_stack_enr = OpStackEnr::new(u.arbitrary()?, 0); + let bytes = alloy_rlp::encode(op_stack_enr).to_vec(); + let decoded = OpStackEnr::decode(&mut &bytes[..]).unwrap(); + assert_eq!(decoded, op_stack_enr); + Ok(()) + }); + } + + #[test] + fn test_is_valid_node() { + let key = CombinedKey::generate_secp256k1(); + let mut enr = Enr::::builder().build(&key).unwrap(); + let op_stack_enr = OpStackEnr::new(10, 0); + let mut op_stack_bytes = Vec::new(); + op_stack_enr.encode(&mut op_stack_bytes); + enr.insert_raw_rlp(OP_CL_KEY, op_stack_bytes.into(), &key).unwrap(); + assert!(OpStackEnr::is_valid_node(&enr, 10)); + assert!(!OpStackEnr::is_valid_node(&enr, 11)); + } + + #[test] + fn test_is_valid_node_invalid_version() { + let key = CombinedKey::generate_secp256k1(); + let mut enr = Enr::::builder().build(&key).unwrap(); + let op_stack_enr = OpStackEnr::new(10, 1); + let mut op_stack_bytes = Vec::new(); + op_stack_enr.encode(&mut op_stack_bytes); + enr.insert_raw_rlp(OP_CL_KEY, op_stack_bytes.into(), &key).unwrap(); + assert!(!OpStackEnr::is_valid_node(&enr, 10)); + } + + #[test] + fn test_op_mainnet_enr() { + let op_enr = OpStackEnr::new(10, 0); + let bytes = alloy_rlp::encode(op_enr).to_vec(); + assert_eq!(Bytes::from(bytes.clone()), bytes!("820A00")); + let decoded = OpStackEnr::decode(&mut &bytes[..]).unwrap(); + assert_eq!(decoded, op_enr); + } + + #[test] + fn test_base_mainnet_enr() { + let base_enr = OpStackEnr::new(8453, 0); + let bytes = alloy_rlp::encode(base_enr).to_vec(); + assert_eq!(Bytes::from(bytes.clone()), bytes!("83854200")); + let decoded = OpStackEnr::decode(&mut &bytes[..]).unwrap(); + assert_eq!(decoded, base_enr); + } +} diff --git a/crates/services/net/src/types/mod.rs b/crates/services/net/src/types/mod.rs new file mode 100644 index 000000000..3f1a6af22 --- /dev/null +++ b/crates/services/net/src/types/mod.rs @@ -0,0 +1,4 @@ +//! Common types for the Networking Crate. + +pub mod enr; +pub mod peer; diff --git a/crates/services/net/src/types/peer.rs b/crates/services/net/src/types/peer.rs new file mode 100644 index 000000000..0aa042445 --- /dev/null +++ b/crates/services/net/src/types/peer.rs @@ -0,0 +1,141 @@ +//! Peer Types + +#[cfg(any(test, feature = "arbitrary"))] +use arbitrary::{Arbitrary, Unstructured}; +use discv5::enr::{CombinedKey, Enr}; +use libp2p::{multiaddr::Protocol, Multiaddr}; +use std::net::{IpAddr, SocketAddr}; + +/// A wrapper around a peer's [SocketAddr]. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Peer { + /// The peer's [SocketAddr]. + pub socket: SocketAddr, +} + +/// An error that can occur when converting types to a [Peer]. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum PeerConversionError { + /// The IP Address is missing. + #[error("IP address is missing")] + MissingIp, + /// The port is missing. + #[error("port is missing")] + MissingPort, +} + +#[cfg(any(test, feature = "arbitrary"))] +impl<'a> Arbitrary<'a> for Peer { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + match u.arbitrary::()? { + true => { + let ipv6 = u.arbitrary::<[u8; 16]>()?; + let port = u.arbitrary::()?; + Ok(Peer { socket: SocketAddr::new(IpAddr::V6(ipv6.into()), port) }) + } + false => { + let ipv4 = u.arbitrary::()?; + let port = u.arbitrary::()?; + Ok(Peer { socket: SocketAddr::new(IpAddr::V4([ipv4; 4].into()), port) }) + } + } + } +} + +impl TryFrom<&Enr> for Peer { + type Error = PeerConversionError; + + /// Converts an [Enr] to a Peer + fn try_from(value: &Enr) -> Result { + let ip = value.ip4().ok_or(PeerConversionError::MissingIp)?; + let port = value.tcp4().ok_or(PeerConversionError::MissingPort)?; + let socket = SocketAddr::new(IpAddr::V4(ip), port); + Ok(Peer { socket }) + } +} + +impl From for Multiaddr { + /// Converts a Peer to a [Multiaddr] + fn from(value: Peer) -> Self { + let mut multiaddr = Multiaddr::empty(); + match value.socket.ip() { + IpAddr::V4(ip) => multiaddr.push(Protocol::Ip4(ip)), + IpAddr::V6(ip) => multiaddr.push(Protocol::Ip6(ip)), + } + multiaddr.push(Protocol::Tcp(value.socket.port())); + multiaddr + } +} + +impl TryFrom<&Multiaddr> for Peer { + type Error = PeerConversionError; + + /// Converts a [Multiaddr] to a Peer + fn try_from(value: &Multiaddr) -> Result { + let mut ip = None; + let mut port = None; + for protocol in value.iter() { + match protocol { + Protocol::Ip4(ip4) => { + ip = Some(IpAddr::V4(ip4)); + } + Protocol::Ip6(ip6) => { + ip = Some(IpAddr::V6(ip6)); + } + Protocol::Tcp(tcp) => { + port = Some(tcp); + } + _ => {} + } + } + let ip = ip.ok_or(PeerConversionError::MissingIp)?; + let port = port.ok_or(PeerConversionError::MissingPort)?; + Ok(Peer { socket: SocketAddr::new(ip, port) }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_peer_to_multiaddr() { + arbtest::arbtest(|u| { + let peer = Peer::arbitrary(u)?; + let mut multiaddr = Multiaddr::from(peer.clone()); + // This will be ignored since only the ipv4, ipv6, and tcp protocols are supported. + multiaddr.push(libp2p::multiaddr::Protocol::Dccp(10)); + let peer2 = + Peer::try_from(&multiaddr).map_err(|_| arbitrary::Error::IncorrectFormat)?; + assert_eq!(peer, peer2); + Ok(()) + }); + } + + #[test] + fn test_peer_from_enr_without_ip() { + let key = CombinedKey::generate_secp256k1(); + let enr = Enr::::builder().build(&key).unwrap(); + let err = Peer::try_from(&enr).unwrap_err(); + assert_eq!(err, PeerConversionError::MissingIp); + } + + #[test] + fn test_peer_from_enr_without_port() { + let key = CombinedKey::generate_secp256k1(); + let ip = std::net::Ipv4Addr::new(192, 168, 0, 1); + let enr = Enr::::builder().ip4(ip).build(&key).unwrap(); + let err = Peer::try_from(&enr).unwrap_err(); + assert_eq!(err, PeerConversionError::MissingPort); + } + + #[test] + fn test_peer_from_enr_succeeds() { + let key = CombinedKey::generate_secp256k1(); + let ip = std::net::Ipv4Addr::new(192, 168, 0, 1); + let port = 30303; + let enr = Enr::::builder().ip4(ip).tcp4(port).build(&key).unwrap(); + let peer = Peer::try_from(&enr).unwrap(); + assert_eq!(peer.socket, SocketAddr::new(IpAddr::V4(ip), port)); + } +} diff --git a/crates/services/providers-alloy/Cargo.toml b/crates/services/providers-alloy/Cargo.toml index b43d00f79..af69e3a06 100644 --- a/crates/services/providers-alloy/Cargo.toml +++ b/crates/services/providers-alloy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kona-providers-alloy" version = "0.1.0" -description = "Alloy-backed providers for hilo" +description = "Alloy Backed Providers" edition.workspace = true authors.workspace = true diff --git a/crates/services/providers-alloy/src/lib.rs b/crates/services/providers-alloy/src/lib.rs index ce30cf6d9..647afb2fd 100644 --- a/crates/services/providers-alloy/src/lib.rs +++ b/crates/services/providers-alloy/src/lib.rs @@ -1,5 +1,9 @@ #![doc = include_str!("../README.md")] -#![doc(issue_tracker_base_url = "https://github.com/op-rs/hilo/issues/")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico", + issue_tracker_base_url = "https://github.com/op-rs/kona/issues/" +)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] diff --git a/justfile b/justfile index a0cd37088..ad7e0c287 100644 --- a/justfile +++ b/justfile @@ -105,7 +105,7 @@ build-cannon *args='': --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/op-rs/kona/cannon-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host --exclude kona-providers-alloy + ghcr.io/op-rs/kona/cannon-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host --exclude kona-providers-alloy --exclude kona-net # Build for the `asterisc` target. Any crates that require the stdlib are excluded from the build for this target. build-asterisc *args='': @@ -114,7 +114,7 @@ build-asterisc *args='': --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/op-rs/kona/asterisc-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host --exclude kona-providers-alloy + ghcr.io/op-rs/kona/asterisc-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host --exclude kona-providers-alloy --exclude kona-net # Clones and checks out the monorepo at the commit present in `.monorepo` monorepo: