From a7f742ffaf4414c7f86633759985cc4fd565a5bf Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 10 Nov 2024 18:07:26 -0500 Subject: [PATCH] feat: net crate --- Cargo.lock | 2479 +++++++++++++++++++++++-- Cargo.toml | 17 + crates/net/Cargo.toml | 47 + crates/net/README.md | 42 + crates/net/src/builder.rs | 458 +++++ crates/net/src/discovery/bootnodes.rs | 35 + crates/net/src/discovery/builder.rs | 101 + crates/net/src/discovery/driver.rs | 119 ++ crates/net/src/discovery/mod.rs | 5 + crates/net/src/driver.rs | 69 + crates/net/src/gossip/behaviour.rs | 81 + crates/net/src/gossip/config.rs | 118 ++ crates/net/src/gossip/driver.rs | 90 + crates/net/src/gossip/event.rs | 27 + crates/net/src/gossip/handler.rs | 129 ++ crates/net/src/gossip/mod.rs | 7 + crates/net/src/lib.rs | 10 + crates/net/src/types/enr.rs | 95 + crates/net/src/types/mod.rs | 4 + crates/net/src/types/peer.rs | 129 ++ 20 files changed, 3886 insertions(+), 176 deletions(-) create mode 100644 crates/net/Cargo.toml create mode 100644 crates/net/README.md create mode 100644 crates/net/src/builder.rs create mode 100644 crates/net/src/discovery/bootnodes.rs create mode 100644 crates/net/src/discovery/builder.rs create mode 100644 crates/net/src/discovery/driver.rs create mode 100644 crates/net/src/discovery/mod.rs create mode 100644 crates/net/src/driver.rs create mode 100644 crates/net/src/gossip/behaviour.rs create mode 100644 crates/net/src/gossip/config.rs create mode 100644 crates/net/src/gossip/driver.rs create mode 100644 crates/net/src/gossip/event.rs create mode 100644 crates/net/src/gossip/handler.rs create mode 100644 crates/net/src/gossip/mod.rs create mode 100644 crates/net/src/lib.rs create mode 100644 crates/net/src/types/enr.rs create mode 100644 crates/net/src/types/mod.rs create mode 100644 crates/net/src/types/peer.rs diff --git a/Cargo.lock b/Cargo.lock index 533241f..c6d58e8 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" @@ -30,6 +65,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -38,9 +82,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "611cc2ae7d2e242c457e4be7f97036b8ad9ca152b499f53faf99b1ed8fc2553f" [[package]] name = "alloy-chains" @@ -55,9 +99,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54bba85233b8cd6bad2dccba685af6836bfcb539202731091eb40c474ba6fa12" +checksum = "b19fd285b55dd39ae0dbc37481ad9f5f48898726f76335a2d6167a85a5fa41da" dependencies = [ "alloy-eips", "alloy-primitives", @@ -96,9 +140,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655929ddc3cd1af9f7f8a3a401e40eb67113edd0aa308d7071ec7375a74d1cc6" +checksum = "21aff0f2c921246398cad88e32a1d8ec14359b183afbc3dcb816873714cafc1a" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -107,16 +151,18 @@ dependencies = [ "alloy-serde", "c-kzg", "derive_more", + "ethereum_ssz", + "ethereum_ssz_derive", "once_cell", "serde", - "sha2", + "sha2 0.10.8", ] [[package]] name = "alloy-genesis" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ff9ecd6f59d42894fbe1c5bab069b6a37980d95b2a94ac7db656a7c594aa42" +checksum = "a76d899cfbfa13c5ed044383b7ae0e6a4d6ffcad3fd25e4acf71ff1c255ddae0" dependencies = [ "alloy-primitives", "alloy-serde", @@ -125,9 +171,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb5c84eddbcdc61f310778fda03d925a6a321f642a988b1ee71f6ec32c5f21d" +checksum = "e244937365749c09c403d3054de39cc7dd46e3c3a12e5b164106af4903011ab1" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -139,9 +185,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f7b36f32cd9d6a1eff3a969fcb131e3d8190b7c38177645b5e6262a9da68e4" +checksum = "0a28811461dc37e28db92b6d3a8c03a5883f2100b270a6294af00710bf4a0be4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -162,9 +208,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14a13d3869e3a1c011165136d489b5f57fee0329964b7bfebc8d55e38572c02" +checksum = "3e517c44a97e753f10dc0736215ba4677da5e2fbc1451e3e76902e02cd6cff12" dependencies = [ "alloy-consensus", "alloy-eips", @@ -175,9 +221,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "906d513e181a203783b3eea1821bb42d188f5c99a370e69e9ddf44bc4fb4b568" +checksum = "15bf1a4b35b071c2d6f21fd3d32b8c5466cb7ed31fd4a4473a4e2ce180729121" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -197,11 +243,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5" dependencies = [ "alloy-rlp", + "arbitrary", "bytes", "cfg-if", "const-hex", + "derive_arbitrary", "derive_more", "foldhash", + "getrandom", "hashbrown 0.15.1", "hex-literal", "indexmap 2.6.0", @@ -210,6 +259,7 @@ dependencies = [ "keccak-asm", "paste", "proptest", + "proptest-derive", "rand", "ruint", "rustc-hash", @@ -220,9 +270,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8a0398d7fe6a4141739bfaf57ad8db15d76a65fd8c7df859773fc65ac24ba2f" +checksum = "56befb85784c7eb4f163b9aed7cdcaba09d5b07f8e59d6c12ad0ce1acf67c0fd" dependencies = [ "alloy-chains", "alloy-consensus", @@ -279,9 +329,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db566ff5b504fc16f2e6943b103d26a243438e74c8515efcd2e10c82101fafae" +checksum = "cb49d38b3279a07e864d973323534a2c4a845e16f2c0153a509a3abcc01da7b1" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -302,9 +352,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "277f84f4b36534b48278e6581c267202b6186a32ce472e7e0d0a6c27a7cddce0" +checksum = "dab9821d5a73f56512ddd8e3db89a5bbb285353129b271c4ad6803a37c4e00ce" dependencies = [ "alloy-eips", "alloy-primitives", @@ -316,9 +366,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5a591c9b2a58d5168867083d4c81a78089d6a90669b57b125800c07ee1dd6d" +checksum = "5ed9e7b3233cb3e0aaeaedc4e21e1ea9d99e947a7206241a9f9521c138193978" dependencies = [ "alloy-consensus", "alloy-eips", @@ -326,15 +376,17 @@ dependencies = [ "alloy-rlp", "alloy-serde", "derive_more", + "ethereum_ssz", + "ethereum_ssz_derive", "serde", "strum", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87af056add05e5cf6994424725354d02d1587098831b59748365c79fd3896d2c" +checksum = "be10f130b8be7c2351a3ea64b4bf07020fde5be8d1ac18db9a9a3496aa22bb19" dependencies = [ "alloy-consensus", "alloy-eips", @@ -351,9 +403,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed60ee9deecc68565aa74d810129c45009fad7ec4317b99859f45f8608fa4fb4" +checksum = "1493df14770a23b1e32d22c66fa22508d09e0a99d6923a45f179ff7887ca0cef" dependencies = [ "alloy-primitives", "serde", @@ -362,9 +414,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bfec8f78014a8c9ebc1d6ddcc951f8aa598fd0d061e0971a3a5f90bcabfdc" +checksum = "ebff64a3b4062eba217404700d1517b9bf3ff9a7a5b2dd03f1cf8aeec3e9a6b8" dependencies = [ "alloy-primitives", "async-trait", @@ -434,12 +486,12 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6102fe2d5d812e0ad9da1997f534cf79a37e930f8bf8c9cd3fd30f817ccdf6da" +checksum = "64534da7f71ecca86b3449adec19b7942fb0905b9f392f60054a02a5f686f71f" dependencies = [ "alloy-json-rpc", - "base64", + "base64 0.22.1", "futures-util", "futures-utils-wasm", "serde", @@ -454,9 +506,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d15dcba0b43725f293ce5d3383b50d112a4f4eb15f197ff791b266335ac18b" +checksum = "617b5ab96f4fb64ef697a84c68ec8534c062baafbdb0529c34aaee43324f0d5a" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -482,6 +534,30 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arbtest" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23909d5fb517fac2a8a4c887e847dbe41dd22ec46914586f5727980d0a193fdc" +dependencies = [ + "arbitrary", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -606,12 +682,93 @@ dependencies = [ "rand", ] +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[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", + "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.87", + "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.87", +] + +[[package]] +name = "asn1_der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" + +[[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" @@ -645,12 +802,36 @@ dependencies = [ "syn 2.0.87", ] +[[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 = "auto_impl" version = "1.2.0" @@ -680,15 +861,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" @@ -716,6 +909,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" @@ -734,6 +933,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" @@ -774,6 +991,15 @@ dependencies = [ "alloc-no-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.16.0" @@ -818,9 +1044,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.36" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "shlex", ] @@ -831,6 +1057,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.38" @@ -841,7 +1097,27 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets", + "windows-targets 0.52.6", +] + +[[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 = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", ] [[package]] @@ -888,6 +1164,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 = "cpufeatures" version = "0.2.14" @@ -928,9 +1213,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "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.87", +] + [[package]] name = "darling" version = "0.20.10" @@ -981,8 +1313,45 @@ dependencies = [ ] [[package]] -name = "der" -version = "0.7.9" +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-encoding-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +dependencies = [ + "data-encoding", + "syn 1.0.109", +] + +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ @@ -990,6 +1359,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" @@ -1011,6 +1394,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "derive_more" version = "1.0.0" @@ -1048,12 +1442,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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "898d136ecb64116ec68aecf14d889bd30f8b1fe0c19e262953f7388dbe77052e" +dependencies = [ + "aes", + "aes-gcm", + "alloy-rlp", + "arrayvec", + "ctr", + "delay_map", + "enr", + "fnv", + "futures", + "hashlink", + "hex", + "hkdf", + "lazy_static", + "lru", + "more-asserts", + "parking_lot", + "rand", + "smallvec", + "socket2", + "tokio", + "tracing", + "uint 0.10.0", + "zeroize", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1065,6 +1490,12 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +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" @@ -1085,6 +1516,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", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.13.0" @@ -1119,6 +1575,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", + "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.87", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1135,11 +1622,83 @@ dependencies = [ "windows-sys 0.52.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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfbba28f4f3f32d92c06a64f5bf6c4537b5d4e21f28c689bd2bbaecfea4e0d3e" +dependencies = [ + "alloy-primitives", + "derivative", + "ethereum_serde_utils", + "itertools 0.13.0", + "serde", + "serde_derive", + "smallvec", + "typenum", +] + +[[package]] +name = "ethereum_ssz_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d37845ba7c16bf4be8be4b5786f03a2ba5f2fda0d7f9e7cb2282f69cff420d7" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fastrlp" @@ -1162,6 +1721,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 = "fixed-hash" version = "0.8.0" @@ -1256,6 +1821,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -1264,6 +1830,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -1275,6 +1851,17 @@ dependencies = [ "syn 2.0.87", ] +[[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" @@ -1287,6 +1874,23 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -1333,6 +1937,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1356,6 +1970,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 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.6" @@ -1367,7 +2000,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.1.0", "indexmap 2.6.0", "slab", "tokio", @@ -1392,6 +2025,9 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -1405,6 +2041,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" @@ -1417,6 +2062,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1433,33 +2084,148 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] -name = "hmac" -version = "0.12.1" +name = "hex_fmt" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" [[package]] -name = "http" -version = "1.1.0" +name = "hickory-proto" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" dependencies = [ - "bytes", - "fnv", - "itoa", + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "socket2", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "hickory-resolver" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" dependencies = [ - "bytes", - "http", + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", ] [[package]] @@ -1470,8 +2236,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1481,6 +2247,36 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +[[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.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +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.5.0" @@ -1490,9 +2286,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -1508,8 +2304,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http", - "hyper", + "http 1.1.0", + "hyper 1.5.0", "hyper-util", "rustls", "rustls-pki-types", @@ -1526,7 +2322,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -1543,9 +2339,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", - "hyper", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", @@ -1564,7 +2360,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -1700,6 +2496,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "1.0.3" @@ -1721,6 +2527,54 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "if-watch" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +dependencies = [ + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "system-configuration 0.5.1", + "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.31", + "log", + "rand", + "tokio", + "url", + "xmltree", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -1741,6 +2595,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.3" @@ -1758,11 +2618,42 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ + "arbitrary", "equivalent", "hashbrown 0.15.1", "serde", ] +[[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 = "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.10.1" @@ -1812,7 +2703,8 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2", + "sha2 0.10.8", + "signature", ] [[package]] @@ -1854,7 +2746,7 @@ dependencies = [ "op-alloy-genesis", "op-alloy-protocol", "op-alloy-rpc-types-engine", - "spin", + "spin 0.9.8", "tracing", "tracing-subscriber", ] @@ -1865,14 +2757,14 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libm" @@ -1880,6 +2772,420 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +[[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", + "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", +] + +[[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", + "rw-stream-sink", + "smallvec", + "thiserror", + "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", + "hex_fmt", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand", + "regex", + "sha2 0.10.8", + "smallvec", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "hkdf", + "libsecp256k1", + "multihash", + "quick-protobuf", + "rand", + "sha2 0.10.8", + "thiserror", + "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", + "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", + "sha2 0.10.8", + "snow", + "static_assertions", + "thiserror", + "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", + "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", + "ring 0.17.8", + "rustls", + "socket2", + "thiserror", + "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", + "multistream-select", + "once_cell", + "rand", + "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.87", +] + +[[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", + "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", + "tracing", + "yamux 0.12.1", + "yamux 0.13.3", +] + +[[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", + "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 = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1898,73 +3204,247 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ - "autocfg", - "scopeguard", + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.1", +] + +[[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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" +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 = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] -name = "log" -version = "0.4.22" +name = "netlink-packet-core" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] [[package]] -name = "lru" -version = "0.12.5" +name = "netlink-packet-route" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ - "hashbrown 0.15.1", + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", ] [[package]] -name = "memchr" -version = "2.7.4" +name = "netlink-packet-utils" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] [[package]] -name = "mime" -version = "0.3.17" +name = "netlink-proto" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] [[package]] -name = "miniz_oxide" -version = "0.8.0" +name = "netlink-sys" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ - "adler2", + "bytes", + "futures", + "libc", + "log", + "tokio", ] [[package]] -name = "mio" -version = "1.0.2" +name = "nix" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "hermit-abi", + "bitflags 1.3.2", + "cfg-if", "libc", - "wasi", - "windows-sys 0.52.0", ] [[package]] -name = "native-tls" -version = "0.2.12" +name = "nohash-hasher" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "memchr", + "minimal-lexical", ] [[package]] @@ -2018,7 +3498,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -2051,6 +3531,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.2" @@ -2059,9 +3548,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "op-alloy-consensus" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabf6e7d7d63b2c6ed746b24d334e16388c6c3921bc50172440c72aa923c6b4a" +checksum = "e33097177de330b1a83e0a882ae752ad55f23962b1e310176d1623655c18421e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -2070,14 +3559,14 @@ dependencies = [ "alloy-serde", "derive_more", "serde", - "spin", + "spin 0.9.8", ] [[package]] name = "op-alloy-genesis" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f901aa077832e22820c644d63d2e5e48601eed0f06e40f2a26d1b2a89bd17dec" +checksum = "2232ff799352932fc5484e1c63ee7bb1e74a79ac7b94a4f7318560fba21167de" dependencies = [ "alloy-consensus", "alloy-eips", @@ -2089,9 +3578,9 @@ dependencies = [ [[package]] name = "op-alloy-protocol" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9226c7618f45f1d1e1f1112230818d5cfa719da9f5ca05fa28eaeb44d024181" +checksum = "a566c421638a3b655a2aaf59fbbdee017a7dce6acfbacead219861e14654b98d" dependencies = [ "alloy-consensus", "alloy-eips", @@ -2104,32 +3593,40 @@ dependencies = [ "op-alloy-genesis", "serde", "tracing", - "unsigned-varint", + "unsigned-varint 0.8.0", ] [[package]] name = "op-alloy-rpc-types-engine" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a5b505325e343b299b1c574b2b8542f6ac3101e0d92a1c909b2d7dd74665f1" +checksum = "f2a270e6370a0fa8a673e29bcd436cbb67b5dc88cefc1d00fbf2382673894f71" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "alloy-serde", "derive_more", + "ethereum_ssz", "op-alloy-consensus", "op-alloy-protocol", "serde", + "snap", ] +[[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.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -2155,6 +3652,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.4.0+3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.104" @@ -2163,6 +3669,7 @@ checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -2199,6 +3706,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -2219,7 +3732,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2228,6 +3741,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" @@ -2293,6 +3816,44 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[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" @@ -2316,7 +3877,7 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "uint", + "uint 0.9.5", ] [[package]] @@ -2359,6 +3920,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.87", +] + [[package]] name = "proptest" version = "1.5.0" @@ -2367,7 +3951,7 @@ checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand", @@ -2379,12 +3963,95 @@ dependencies = [ "unarray", ] +[[package]] +name = "proptest-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "quick-error" 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", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.37" @@ -2440,13 +4107,48 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rcgen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" +dependencies = [ + "pem", + "ring 0.16.20", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags", + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] @@ -2461,16 +4163,16 @@ version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-rustls", "hyper-tls", "hyper-util", @@ -2487,7 +4189,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", - "system-configuration", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tower-service", @@ -2498,16 +4200,41 @@ 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 = "rfc6979" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] +[[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" @@ -2518,8 +4245,8 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -2533,6 +4260,21 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rtnetlink" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +dependencies = [ + "futures", + "log", + "netlink-packet-route", + "netlink-proto", + "nix", + "thiserror", + "tokio", +] + [[package]] name = "ruint" version = "1.12.3" @@ -2540,6 +4282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" dependencies = [ "alloy-rlp", + "arbitrary", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", @@ -2599,13 +4342,22 @@ dependencies = [ "semver 1.0.23", ] +[[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.39" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ - "bitflags", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -2619,8 +4371,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "once_cell", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -2640,15 +4393,25 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +[[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" 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]] @@ -2669,6 +4432,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.18" @@ -2721,7 +4495,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -2730,9 +4504,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -2823,7 +4597,7 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -2847,6 +4621,19 @@ dependencies = [ "syn 2.0.87", ] +[[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" @@ -2927,6 +4714,29 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[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", + "ring 0.17.8", + "rustc_version 0.4.1", + "sha2 0.10.8", + "subtle", +] + [[package]] name = "socket2" version = "0.5.7" @@ -2937,6 +4747,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" @@ -3039,6 +4855,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "superchain-net" +version = "0.0.0" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-engine", + "arbitrary", + "arbtest", + "discv5", + "eyre", + "futures", + "lazy_static", + "libp2p", + "libp2p-identity", + "op-alloy-rpc-types-engine", + "openssl", + "snap", + "tokio", + "tracing", + "unsigned-varint 0.8.0", +] + [[package]] name = "superchain-registry" version = "0.11.0" @@ -3111,15 +4950,36 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys 0.5.0", +] + [[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -3140,9 +5000,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -3153,18 +5013,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -3240,11 +5100,26 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.41.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -3312,6 +5187,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", + "slab", "tokio", ] @@ -3364,6 +5240,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3445,18 +5322,45 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicode-bidi" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" + [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -3469,12 +5373,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" @@ -3488,7 +5414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna", + "idna 1.0.3", "percent-encoding", ] @@ -3522,6 +5448,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.0" @@ -3637,6 +5569,22 @@ 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 = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -3659,13 +5607,32 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core 0.51.1", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3676,7 +5643,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3685,7 +5652,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]] @@ -3695,7 +5662,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets", + "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]] @@ -3704,7 +5680,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]] @@ -3713,7 +5689,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]] @@ -3722,28 +5713,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" @@ -3756,24 +5765,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" @@ -3789,6 +5822,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 = "write16" version = "1.0.0" @@ -3810,6 +5853,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", + "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", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" + +[[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", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "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.4" diff --git a/Cargo.toml b/Cargo.toml index 6e594ac..918c77f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,22 +55,39 @@ alloy-transport = { version = "0.6.1", default-features = false } alloy-rpc-client = { version = "0.6.1", default-features = false } alloy-node-bindings = { version = "0.6.1", default-features = false } alloy-transport-http = { version = "0.6.1", default-features = false } +alloy-rpc-types-eth = { version = "0.6.1", default-features = false } alloy-rpc-types-beacon = { version = "0.6.1", default-features = false } +alloy-rpc-types-engine = { version = "0.6.1", default-features = false } # OP Alloy op-alloy-genesis = { version = "0.6.2", default-features = false } op-alloy-protocol = { version = "0.6.2", default-features = false } op-alloy-consensus = { version = "0.6.2", default-features = false } +op-alloy-rpc-types-engine = { version = "0.6.2", default-features = false } # Serialization serde = { version = "1.0.214", default-features = false } serde_json = { version = "1.0.132", default-features = false } +# Networking +snap = "1.1.1" +discv5 = "0.9.0" +libp2p = "0.54.1" +openssl = "0.10.68" +libp2p-identity = "0.2.9" + +# Testing +arbtest = "0.3" +arbitrary = "1" + # Misc lru = "0.12.5" +eyre = "0.6.12" tokio = "1.41.0" +futures = "0.3.31" reqwest = "0.12.9" async-trait = "0.1.83" +unsigned-varint = "0.8.0" tracing = { version = "0.1.40", default-features = false } derive_more = { version = "1.0.0", default-features = false } lazy_static = { version = "1.5.0", default-features = false } diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml new file mode 100644 index 0000000..7470ebc --- /dev/null +++ b/crates/net/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "superchain-net" +description = "Networking library for the OP Stack" +version = "0.0.0" +edition.workspace = true +authors.workspace = true +license.workspace = true +keywords.workspace = true +repository.workspace = true +categories.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 +eyre.workspace = true +tokio.workspace = true +tracing.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/net/README.md b/crates/net/README.md new file mode 100644 index 0000000..692301f --- /dev/null +++ b/crates/net/README.md @@ -0,0 +1,42 @@ +## Consensus Network Library + +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 superchain_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/net/src/builder.rs b/crates/net/src/builder.rs new file mode 100644 index 0000000..b4dd9b6 --- /dev/null +++ b/crates/net/src/builder.rs @@ -0,0 +1,458 @@ +//! Network Builder Module. + +use alloy_primitives::Address; +use discv5::{Config, ListenConfig}; +use eyre::Result; +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, + driver::NetworkDriver, + gossip::{behaviour::Behaviour, config, driver::GossipDriver, handler::BlockHandler}, +}; + +/// 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 superchain_net::gossip::config; + /// use superchain_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 std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// use superchain_net::builder::NetworkDriverBuilder; + /// + /// 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 superchain_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()?, + }; + let unsafe_block_signer = + self.unsafe_block_signer.ok_or_else(|| eyre::eyre!("unsafe block signer not set"))?; + let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; + + // 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(), + )? + .with_behaviour(|_| behaviour)? + .with_swarm_config(|c| c.with_idle_connection_timeout(timeout)) + .build(); + + let gossip_addr = + self.gossip_addr.take().ok_or(eyre::eyre!("gossip_addr address not set"))?; + 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.to_string(), "unsafe block signer not set"); + } + + #[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.to_string(), "chain ID not set"); + } + + #[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.to_string(), "gossip_addr address not set"); + } + + #[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/net/src/discovery/bootnodes.rs b/crates/net/src/discovery/bootnodes.rs new file mode 100644 index 0000000..6c29020 --- /dev/null +++ b/crates/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/net/src/discovery/builder.rs b/crates/net/src/discovery/builder.rs new file mode 100644 index 0000000..d10fb9a --- /dev/null +++ b/crates/net/src/discovery/builder.rs @@ -0,0 +1,101 @@ +//! 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 eyre::{Report, Result}; +use std::net::SocketAddr; + +use crate::types::enr::OP_CL_KEY; + +/// 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_else(|| eyre::eyre!("chain ID not set"))?; + 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_else(|| eyre::eyre!("listen config not set"))?; + 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)?; + + let disc = Discv5::new(enr, key, config) + .map_err(|_| eyre::eyre!("could not create disc service"))?; + + Ok(DiscoveryDriver::new(disc, chain_id)) + } +} diff --git a/crates/net/src/discovery/driver.rs b/crates/net/src/discovery/driver.rs new file mode 100644 index 0000000..588ccc0 --- /dev/null +++ b/crates/net/src/discovery/driver.rs @@ -0,0 +1,119 @@ +//! Discovery Module. + +use eyre::Result; +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 std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// use superchain_net::discovery::builder::DiscoveryBuilder; + /// + /// #[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().expect("Failed to start discovery service"); + /// + /// loop { + /// if let Some(peer) = peer_recv.recv().await { + /// println!("Received peer: {:?}", peer); + /// } + /// } + /// } + /// ``` + pub fn start(mut self) -> Result> { + // 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; + } + }); + + Ok(recv) + } +} diff --git a/crates/net/src/discovery/mod.rs b/crates/net/src/discovery/mod.rs new file mode 100644 index 0000000..633c76b --- /dev/null +++ b/crates/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/net/src/driver.rs b/crates/net/src/driver.rs new file mode 100644 index 0000000..efd26fb --- /dev/null +++ b/crates/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 eyre::Result; +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<()> { + 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/net/src/gossip/behaviour.rs b/crates/net/src/gossip/behaviour.rs new file mode 100644 index 0000000..8ee1fdc --- /dev/null +++ b/crates/net/src/gossip/behaviour.rs @@ -0,0 +1,81 @@ +//! Network Behaviour Module. + +use eyre::Result; +use libp2p::{ + gossipsub::{Config, IdentTopic, MessageAuthenticity}, + swarm::NetworkBehaviour, +}; + +use super::{event::Event, handler::Handler}; + +/// 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(|_| eyre::eyre!("gossipsub behaviour creation failed"))?; + + handlers + .iter() + .flat_map(|handler| { + handler + .topics() + .iter() + .map(|topic| { + let topic = IdentTopic::new(topic.to_string()); + gossipsub.subscribe(&topic).map_err(|_| eyre::eyre!("subscription failed")) + }) + .collect::>() + }) + .collect::>>()?; + + 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/net/src/gossip/config.rs b/crates/net/src/gossip/config.rs new file mode 100644 index 0000000..01aad8e --- /dev/null +++ b/crates/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/net/src/gossip/driver.rs b/crates/net/src/gossip/driver.rs new file mode 100644 index 0000000..054f4d5 --- /dev/null +++ b/crates/net/src/gossip/driver.rs @@ -0,0 +1,90 @@ +//! Consensus-layer gossipsub driver for Optimism. + +use crate::gossip::{ + behaviour::Behaviour, + event::Event, + handler::{BlockHandler, Handler}, +}; +use eyre::Result; +use futures::stream::StreamExt; +use libp2p::{swarm::SwarmEvent, Multiaddr, Swarm}; +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<()> { + self.swarm.listen_on(self.addr.clone()).map_err(|_| eyre::eyre!("swarm listen failed"))?; + 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<()> { + let addr: Multiaddr = peer.into(); + self.swarm.dial(addr).map_err(|e| eyre::eyre!("dial failed: {:?}", e))?; + 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/net/src/gossip/event.rs b/crates/net/src/gossip/event.rs new file mode 100644 index 0000000..0175130 --- /dev/null +++ b/crates/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/net/src/gossip/handler.rs b/crates/net/src/gossip/handler.rs new file mode 100644 index 0000000..60e80b8 --- /dev/null +++ b/crates/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/net/src/gossip/mod.rs b/crates/net/src/gossip/mod.rs new file mode 100644 index 0000000..2257a65 --- /dev/null +++ b/crates/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/net/src/lib.rs b/crates/net/src/lib.rs new file mode 100644 index 0000000..94ef225 --- /dev/null +++ b/crates/net/src/lib.rs @@ -0,0 +1,10 @@ +#![doc = include_str!("../README.md")] +#![doc(issue_tracker_base_url = "https://github.com/ithacaxyz/op-rs/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/net/src/types/enr.rs b/crates/net/src/types/enr.rs new file mode 100644 index 0000000..b819b05 --- /dev/null +++ b/crates/net/src/types/enr.rs @@ -0,0 +1,95 @@ +//! 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_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/net/src/types/mod.rs b/crates/net/src/types/mod.rs new file mode 100644 index 0000000..3f1a6af --- /dev/null +++ b/crates/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/net/src/types/peer.rs b/crates/net/src/types/peer.rs new file mode 100644 index 0000000..7e08bb1 --- /dev/null +++ b/crates/net/src/types/peer.rs @@ -0,0 +1,129 @@ +//! Peer Types + +#[cfg(any(test, feature = "arbitrary"))] +use arbitrary::{Arbitrary, Unstructured}; +use discv5::enr::{CombinedKey, Enr}; +use eyre::Result; +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, +} + +#[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 = eyre::Report; + + /// Converts an [Enr] to a Peer + fn try_from(value: &Enr) -> Result { + let ip = value.ip4().ok_or(eyre::eyre!("missing ip"))?; + let port = value.tcp4().ok_or(eyre::eyre!("missing port"))?; + 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 = eyre::Report; + + /// 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(eyre::eyre!("missing ip"))?; + let port = port.ok_or(eyre::eyre!("missing port"))?; + 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 multiaddr = Multiaddr::from(peer.clone()); + 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.to_string(), "missing ip"); + } + + #[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.to_string(), "missing port"); + } + + #[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)); + } +}