From 471a3a18a3879eeda15d69a869536ae42e306bc5 Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 13:58:59 -0400 Subject: [PATCH 01/16] feat(net): Networking Crate --- Cargo.lock | 302 +++++++++++++++++++++++++++------------- Cargo.toml | 4 + crates/net/Cargo.toml | 15 ++ crates/net/src/lib.rs | 10 ++ crates/net/src/types.rs | 58 ++++++++ 5 files changed, 290 insertions(+), 99 deletions(-) create mode 100644 crates/net/Cargo.toml create mode 100644 crates/net/src/lib.rs create mode 100644 crates/net/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 6bbb756..eeccf72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2873,6 +2873,7 @@ dependencies = [ "hyper-util", "log", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", @@ -4234,6 +4235,43 @@ dependencies = [ "serde", ] +[[package]] +name = "op-alloy-network" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45aa09913f11e914fbd60535133d079529e726ad4605edd3d3047678d37b548" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-rpc-types-eth", + "op-alloy-consensus", + "op-alloy-rpc-types", +] + +[[package]] +name = "op-alloy-rpc-types" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48bf0c126082234c15b6051c1f06d2d666adf68e7de305a5352022f06a84be78" +dependencies = [ + "alloy-network", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "op-alloy-consensus", + "serde", + "serde_json", +] + +[[package]] +name = "op-net" +version = "0.0.0" +dependencies = [ + "alloy", + "kona-primitives", +] + [[package]] name = "op-rs" version = "0.1.0" @@ -4990,6 +5028,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", + "rustls-native-certs", "rustls-pemfile", "rustls-pki-types", "serde", @@ -5022,7 +5061,7 @@ dependencies = [ [[package]] name = "reth" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "aquamarine", @@ -5066,6 +5105,7 @@ dependencies = [ "reth-node-events", "reth-node-metrics", "reth-optimism-primitives", + "reth-optimism-rpc", "reth-payload-builder", "reth-payload-primitives", "reth-payload-validator", @@ -5102,7 +5142,7 @@ dependencies = [ [[package]] name = "reth-auto-seal-consensus" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures-util", "reth-beacon-consensus", @@ -5129,7 +5169,7 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "futures-core", @@ -5152,7 +5192,7 @@ dependencies = [ [[package]] name = "reth-beacon-consensus" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures", "itertools 0.13.0", @@ -5186,7 +5226,7 @@ dependencies = [ [[package]] name = "reth-blockchain-tree" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "aquamarine", "linked_hash_set", @@ -5217,7 +5257,7 @@ dependencies = [ [[package]] name = "reth-blockchain-tree-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-consensus", "reth-execution-errors", @@ -5229,7 +5269,7 @@ dependencies = [ [[package]] name = "reth-chain-state" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "auto_impl", "derive_more 1.0.0", @@ -5251,7 +5291,7 @@ dependencies = [ [[package]] name = "reth-chainspec" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-chains", "alloy-eips", @@ -5271,7 +5311,7 @@ dependencies = [ [[package]] name = "reth-cli-commands" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "ahash", "backon", @@ -5325,7 +5365,7 @@ dependencies = [ [[package]] name = "reth-cli-runner" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-tasks", "tokio", @@ -5335,7 +5375,7 @@ dependencies = [ [[package]] name = "reth-cli-util" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-eips", "alloy-primitives", @@ -5350,7 +5390,7 @@ dependencies = [ [[package]] name = "reth-codecs" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5366,7 +5406,7 @@ dependencies = [ [[package]] name = "reth-codecs-derive" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "convert_case 0.6.0", "proc-macro2", @@ -5377,7 +5417,7 @@ dependencies = [ [[package]] name = "reth-config" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "eyre", "humantime-serde", @@ -5391,7 +5431,7 @@ dependencies = [ [[package]] name = "reth-consensus" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "auto_impl", "derive_more 1.0.0", @@ -5401,7 +5441,7 @@ dependencies = [ [[package]] name = "reth-consensus-common" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chainspec", "reth-consensus", @@ -5411,7 +5451,7 @@ dependencies = [ [[package]] name = "reth-consensus-debug-client" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5434,7 +5474,7 @@ dependencies = [ [[package]] name = "reth-db" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "bytes", "derive_more 1.0.0", @@ -5464,7 +5504,7 @@ dependencies = [ [[package]] name = "reth-db-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "bytes", "derive_more 1.0.0", @@ -5485,7 +5525,7 @@ dependencies = [ [[package]] name = "reth-db-common" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-genesis", "boyer-moore-magiclen", @@ -5511,7 +5551,7 @@ dependencies = [ [[package]] name = "reth-db-models" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "bytes", "modular-bitfield", @@ -5523,7 +5563,7 @@ dependencies = [ [[package]] name = "reth-discv4" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -5547,7 +5587,7 @@ dependencies = [ [[package]] name = "reth-discv5" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -5573,7 +5613,7 @@ dependencies = [ [[package]] name = "reth-dns-discovery" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "data-encoding", @@ -5595,7 +5635,7 @@ dependencies = [ [[package]] name = "reth-downloaders" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "futures", @@ -5622,7 +5662,7 @@ dependencies = [ [[package]] name = "reth-ecies" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "aes 0.8.4", "alloy-primitives", @@ -5653,7 +5693,7 @@ dependencies = [ [[package]] name = "reth-engine-primitives" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chainspec", "reth-payload-primitives", @@ -5663,7 +5703,7 @@ dependencies = [ [[package]] name = "reth-engine-service" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures", "pin-project", @@ -5687,7 +5727,7 @@ dependencies = [ [[package]] name = "reth-engine-tree" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures", "metrics", @@ -5722,7 +5762,7 @@ dependencies = [ [[package]] name = "reth-engine-util" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "eyre", "futures", @@ -5751,7 +5791,7 @@ dependencies = [ [[package]] name = "reth-errors" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-blockchain-tree-api", "reth-consensus", @@ -5764,7 +5804,7 @@ dependencies = [ [[package]] name = "reth-eth-wire" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "bytes", @@ -5789,7 +5829,7 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-chains", "alloy-genesis", @@ -5805,7 +5845,7 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chainspec", "reth-consensus", @@ -5817,7 +5857,7 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "reth-chainspec", @@ -5835,7 +5875,7 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-chains", "alloy-primitives", @@ -5852,7 +5892,7 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-basic-payload-builder", "reth-errors", @@ -5871,7 +5911,7 @@ dependencies = [ [[package]] name = "reth-etl" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "rayon", "reth-db-api", @@ -5881,7 +5921,7 @@ dependencies = [ [[package]] name = "reth-evm" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-eips", "auto_impl", @@ -5899,7 +5939,7 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-eips", "alloy-sol-types", @@ -5914,10 +5954,30 @@ dependencies = [ "revm-primitives", ] +[[package]] +name = "reth-evm-optimism" +version = "1.0.5" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" +dependencies = [ + "reth-chainspec", + "reth-ethereum-forks", + "reth-evm", + "reth-execution-errors", + "reth-execution-types", + "reth-optimism-consensus", + "reth-primitives", + "reth-prune-types", + "reth-revm", + "revm", + "revm-primitives", + "thiserror", + "tracing", +] + [[package]] name = "reth-execution-errors" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-eips", "alloy-primitives", @@ -5933,7 +5993,7 @@ dependencies = [ [[package]] name = "reth-execution-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-execution-errors", "reth-primitives", @@ -5945,7 +6005,7 @@ dependencies = [ [[package]] name = "reth-exex" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "eyre", "futures", @@ -5972,7 +6032,7 @@ dependencies = [ [[package]] name = "reth-exex-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "reth-provider", @@ -5982,7 +6042,7 @@ dependencies = [ [[package]] name = "reth-fs-util" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "serde", "serde_json", @@ -5992,7 +6052,7 @@ dependencies = [ [[package]] name = "reth-ipc" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "async-trait", "bytes", @@ -6013,7 +6073,7 @@ dependencies = [ [[package]] name = "reth-libmdbx" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "bitflags 2.6.0", "byteorder", @@ -6029,7 +6089,7 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "bindgen", "cc", @@ -6038,7 +6098,7 @@ dependencies = [ [[package]] name = "reth-metrics" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures", "metrics", @@ -6050,7 +6110,7 @@ dependencies = [ [[package]] name = "reth-metrics-derive" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "proc-macro2", "quote", @@ -6061,7 +6121,7 @@ dependencies = [ [[package]] name = "reth-net-banlist" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", ] @@ -6069,7 +6129,7 @@ dependencies = [ [[package]] name = "reth-net-nat" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures-util", "reqwest", @@ -6081,7 +6141,7 @@ dependencies = [ [[package]] name = "reth-network" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "aquamarine", @@ -6129,7 +6189,7 @@ dependencies = [ [[package]] name = "reth-network-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "alloy-rpc-types-admin", @@ -6152,7 +6212,7 @@ dependencies = [ [[package]] name = "reth-network-p2p" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "auto_impl", "derive_more 1.0.0", @@ -6170,7 +6230,7 @@ dependencies = [ [[package]] name = "reth-network-peers" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -6185,7 +6245,7 @@ dependencies = [ [[package]] name = "reth-network-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "humantime-serde", "reth-ethereum-forks", @@ -6199,7 +6259,7 @@ dependencies = [ [[package]] name = "reth-nippy-jar" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "anyhow", "bincode", @@ -6219,7 +6279,7 @@ dependencies = [ [[package]] name = "reth-node-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chainspec", "reth-db-api", @@ -6237,7 +6297,7 @@ dependencies = [ [[package]] name = "reth-node-builder" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-network", "aquamarine", @@ -6294,7 +6354,7 @@ dependencies = [ [[package]] name = "reth-node-core" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-genesis", "alloy-rpc-types-engine", @@ -6344,7 +6404,7 @@ dependencies = [ [[package]] name = "reth-node-ethereum" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "eyre", "reth-auto-seal-consensus", @@ -6368,7 +6428,7 @@ dependencies = [ [[package]] name = "reth-node-events" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rpc-types-engine", "futures", @@ -6390,7 +6450,7 @@ dependencies = [ [[package]] name = "reth-node-metrics" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "eyre", "http", @@ -6411,15 +6471,59 @@ dependencies = [ "vergen", ] +[[package]] +name = "reth-optimism-consensus" +version = "1.0.5" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" +dependencies = [ + "reth-chainspec", + "reth-consensus", + "reth-consensus-common", + "reth-primitives", + "tracing", +] + [[package]] name = "reth-optimism-primitives" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" + +[[package]] +name = "reth-optimism-rpc" +version = "1.0.5" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" +dependencies = [ + "alloy-primitives", + "jsonrpsee-types", + "op-alloy-network", + "parking_lot 0.12.3", + "reqwest", + "reth-chainspec", + "reth-evm", + "reth-evm-optimism", + "reth-network-api", + "reth-node-api", + "reth-node-builder", + "reth-primitives", + "reth-provider", + "reth-rpc", + "reth-rpc-eth-api", + "reth-rpc-eth-types", + "reth-rpc-server-types", + "reth-rpc-types", + "reth-tasks", + "reth-transaction-pool", + "revm", + "serde_json", + "thiserror", + "tokio", + "tracing", +] [[package]] name = "reth-payload-builder" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures-util", "metrics", @@ -6441,7 +6545,7 @@ dependencies = [ [[package]] name = "reth-payload-primitives" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chain-state", "reth-chainspec", @@ -6457,7 +6561,7 @@ dependencies = [ [[package]] name = "reth-payload-validator" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chainspec", "reth-primitives", @@ -6468,7 +6572,7 @@ dependencies = [ [[package]] name = "reth-primitives" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6498,7 +6602,7 @@ dependencies = [ [[package]] name = "reth-primitives-traits" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6518,7 +6622,7 @@ dependencies = [ [[package]] name = "reth-provider" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rpc-types-engine", "auto_impl", @@ -6556,7 +6660,7 @@ dependencies = [ [[package]] name = "reth-prune" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "itertools 0.13.0", @@ -6582,7 +6686,7 @@ dependencies = [ [[package]] name = "reth-prune-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "bytes", @@ -6596,7 +6700,7 @@ dependencies = [ [[package]] name = "reth-revm" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "reth-chainspec", "reth-consensus-common", @@ -6611,7 +6715,7 @@ dependencies = [ [[package]] name = "reth-rpc" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-dyn-abi", "alloy-genesis", @@ -6667,7 +6771,7 @@ dependencies = [ [[package]] name = "reth-rpc-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-json-rpc", "jsonrpsee", @@ -6681,7 +6785,7 @@ dependencies = [ [[package]] name = "reth-rpc-builder" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "http", "jsonrpsee", @@ -6714,7 +6818,7 @@ dependencies = [ [[package]] name = "reth-rpc-engine-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "async-trait", "jsonrpsee-core", @@ -6742,7 +6846,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-dyn-abi", "alloy-json-rpc", @@ -6778,7 +6882,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-sol-types", "derive_more 1.0.0", @@ -6816,7 +6920,7 @@ dependencies = [ [[package]] name = "reth-rpc-layer" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rpc-types-engine", "http", @@ -6829,7 +6933,7 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "jsonrpsee-core", @@ -6845,7 +6949,7 @@ dependencies = [ [[package]] name = "reth-rpc-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "alloy-rpc-types", @@ -6863,7 +6967,7 @@ dependencies = [ [[package]] name = "reth-rpc-types-compat" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "alloy-rpc-types", @@ -6875,7 +6979,7 @@ dependencies = [ [[package]] name = "reth-stages" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "futures-util", "itertools 0.13.0", @@ -6909,7 +7013,7 @@ dependencies = [ [[package]] name = "reth-stages-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "aquamarine", @@ -6936,7 +7040,7 @@ dependencies = [ [[package]] name = "reth-stages-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "bytes", @@ -6949,7 +7053,7 @@ dependencies = [ [[package]] name = "reth-static-file" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "parking_lot 0.12.3", @@ -6969,7 +7073,7 @@ dependencies = [ [[package]] name = "reth-static-file-types" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-primitives", "clap", @@ -6981,7 +7085,7 @@ dependencies = [ [[package]] name = "reth-storage-api" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "auto_impl", "reth-chainspec", @@ -6998,7 +7102,7 @@ dependencies = [ [[package]] name = "reth-storage-errors" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "derive_more 1.0.0", @@ -7009,7 +7113,7 @@ dependencies = [ [[package]] name = "reth-tasks" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "auto_impl", "dyn-clone", @@ -7027,7 +7131,7 @@ dependencies = [ [[package]] name = "reth-tokio-util" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "tokio", "tokio-stream", @@ -7037,7 +7141,7 @@ dependencies = [ [[package]] name = "reth-tracing" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "clap", "eyre", @@ -7052,7 +7156,7 @@ dependencies = [ [[package]] name = "reth-transaction-pool" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "aquamarine", @@ -7084,7 +7188,7 @@ dependencies = [ [[package]] name = "reth-trie" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "auto_impl", @@ -7106,7 +7210,7 @@ dependencies = [ [[package]] name = "reth-trie-common" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -7126,7 +7230,7 @@ dependencies = [ [[package]] name = "reth-trie-db" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "auto_impl", @@ -7150,7 +7254,7 @@ dependencies = [ [[package]] name = "reth-trie-parallel" version = "1.0.5" -source = "git+https://github.com/paradigmxyz/reth#ec31b247e9ba927a5efd15b22340cf8abab749a2" +source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rlp", "derive_more 1.0.0", diff --git a/Cargo.toml b/Cargo.toml index 8465434..51ec209 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ categories = ["cryptography", "cryptography::cryptocurrencies"] members = [ "bin/hera", "bin/op-rs", + "crates/net", "crates/kona-providers", "crates/rollup", "crates/ser", @@ -115,6 +116,9 @@ codegen-units = 1 incremental = false [workspace.dependencies] +# Workspace +op-net = { path = "crates/net" } + # Optimism superchain-registry = { version = "0.2.6", default-features = false } kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml new file mode 100644 index 0000000..3dc575c --- /dev/null +++ b/crates/net/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "op-net" +description = "Networking library for OP Stack Consensus" +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.workspace = true +kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } diff --git a/crates/net/src/lib.rs b/crates/net/src/lib.rs new file mode 100644 index 0000000..86aa2df --- /dev/null +++ b/crates/net/src/lib.rs @@ -0,0 +1,10 @@ +//! Consensus Networking Library + +#![doc(issue_tracker_base_url = "https://github.com/paradigmxyz/op-rs/issues/")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(test), no_std)] + +extern crate alloc; + +pub mod types; diff --git a/crates/net/src/types.rs b/crates/net/src/types.rs new file mode 100644 index 0000000..e7f939a --- /dev/null +++ b/crates/net/src/types.rs @@ -0,0 +1,58 @@ +//! Types for the P2P network. + +use alloc::vec::Vec; +use alloy::primitives::{keccak256, Signature, B256}; +use kona_primitives::L2ExecutionPayload; + +/// An envelope around the execution payload for L2. +#[derive(Debug)] +pub struct ExecutionPayloadEnvelope { + /// The execution payload. + pub payload: L2ExecutionPayload, + /// A signature for the payload. + pub signature: Signature, + /// The hash of the payload. + pub hash: PayloadHash, + /// The parent beacon block root. + pub parent_beacon_block_root: Option, +} + +/// Represents the Keccak256 hash of the block +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PayloadHash(B256); + +impl From<&[u8]> for PayloadHash { + /// Returns the Keccak256 hash of a sequence of bytes + fn from(value: &[u8]) -> Self { + Self(keccak256(value)) + } +} + +impl PayloadHash { + /// The expected message that should be signed by the unsafe block signer. + pub fn signature_message(&self, chain_id: u64) -> B256 { + let domain = B256::ZERO; + let chain_id = B256::left_padding_from(&chain_id.to_be_bytes()[..]); + let payload_hash = self.0; + + let data: Vec = + [domain.as_slice(), chain_id.as_slice(), payload_hash.as_slice()].concat(); + + keccak256(data) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy::primitives::b256; + + #[test] + fn test_signature_message() { + let inner = b256!("9999999999999999999999999999999999999999999999999999999999999999"); + let hash = PayloadHash::from(inner.as_slice()); + let chain_id = 10; + let expected = b256!("44a0e2b1aba1aae1771eddae1dcd2ad18a8cdac8891517153f03253e49d3f206"); + assert_eq!(hash.signature_message(chain_id), expected); + } +} From b3cf519ea70c9883331608923a91a9e4982ad9d8 Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 16:28:40 -0400 Subject: [PATCH 02/16] fix(net): p2p work --- Cargo.lock | 1344 +++++++++++++++++++++++++++++++++-- Cargo.toml | 9 + crates/net/Cargo.toml | 17 + crates/net/src/behaviour.rs | 46 ++ crates/net/src/builder.rs | 91 +++ crates/net/src/config.rs | 112 +++ crates/net/src/driver.rs | 88 +++ crates/net/src/event.rs | 27 + crates/net/src/handler.rs | 124 ++++ crates/net/src/lib.rs | 9 +- crates/net/src/types.rs | 109 ++- 11 files changed, 1890 insertions(+), 86 deletions(-) create mode 100644 crates/net/src/behaviour.rs create mode 100644 crates/net/src/builder.rs create mode 100644 crates/net/src/config.rs create mode 100644 crates/net/src/driver.rs create mode 100644 crates/net/src/event.rs create mode 100644 crates/net/src/handler.rs diff --git a/Cargo.lock b/Cargo.lock index eeccf72..ef603e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,16 @@ dependencies = [ "generic-array", ] +[[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.7.5" @@ -62,11 +72,25 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" dependencies = [ - "aead", + "aead 0.4.3", "aes 0.7.5", "cipher 0.3.0", "ctr 0.7.0", - "ghash", + "ghash 0.4.4", + "subtle", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead 0.5.2", + "aes 0.8.4", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.1", "subtle", ] @@ -686,7 +710,7 @@ dependencies = [ "alloy-pubsub", "alloy-transport", "futures", - "http", + "http 1.1.0", "rustls", "serde_json", "tokio", @@ -931,6 +955,45 @@ 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.76", + "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.76", +] + [[package]] name = "asn1_der" version = "0.7.6" @@ -953,6 +1016,36 @@ dependencies = [ "zstd-safe", ] +[[package]] +name = "async-io" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +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.5" @@ -997,12 +1090,36 @@ dependencies = [ "rustc_version 0.4.0", ] +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http 0.2.12", + "log", + "url", +] + [[package]] name = "aurora-engine-modexp" version = "1.1.0" @@ -1186,6 +1303,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -1415,6 +1541,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead 0.5.2", + "chacha20", + "cipher 0.4.4", + "poly1305", + "zeroize", +] + [[package]] name = "chrono" version = "0.4.38" @@ -1447,6 +1597,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1550,6 +1701,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console" version = "0.15.8" @@ -1759,6 +1919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -1954,6 +2115,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" @@ -2080,7 +2255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cafb8ed8d460b7d1c8d4c970270d45ecb5e283179a3945143196624c55cda6ac" dependencies = [ "aes 0.7.5", - "aes-gcm", + "aes-gcm 0.9.2", "alloy-rlp", "arrayvec", "delay_map", @@ -2091,7 +2266,7 @@ dependencies = [ "hex", "hkdf", "lazy_static", - "libp2p", + "libp2p 0.53.2", "lru", "more-asserts", "parking_lot 0.11.2", @@ -2104,12 +2279,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + [[package]] name = "doctest-file" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" +[[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" @@ -2272,6 +2464,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[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" @@ -2433,6 +2646,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -2444,6 +2667,17 @@ dependencies = [ "syn 2.0.76", ] +[[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.30" @@ -2456,6 +2690,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +[[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" @@ -2532,7 +2777,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug", - "polyval", + "polyval 0.5.3", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval 0.6.2", ] [[package]] @@ -2557,7 +2812,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http", + "http 1.1.0", "js-sys", "pin-project", "serde", @@ -2604,6 +2859,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.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.6" @@ -2615,7 +2889,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.1.0", "indexmap 2.4.0", "slab", "tokio", @@ -2701,6 +2975,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" @@ -2716,6 +2996,58 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand 0.8.5", + "socket2 0.5.7", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot 0.12.3", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2768,9 +3100,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -2778,13 +3110,35 @@ dependencies = [ ] [[package]] -name = "http-body" -version = "1.0.1" +name = "http" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", - "http", + "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]] @@ -2795,8 +3149,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2840,6 +3194,30 @@ dependencies = [ "serde", ] +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +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 0.5.7", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.4.1" @@ -2849,9 +3227,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", "httpdate", "itoa", @@ -2868,8 +3246,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http", - "hyper", + "http 1.1.0", + "hyper 1.4.1", "hyper-util", "log", "rustls", @@ -2889,7 +3267,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.4.1", "hyper-util", "native-tls", "tokio", @@ -2906,9 +3284,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", - "hyper", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", "pin-project-lite", "socket2 0.5.7", "tokio", @@ -2966,6 +3344,54 @@ dependencies = [ "unicode-normalization", ] +[[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 0.51.1", +] + +[[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.30", + "log", + "rand 0.8.5", + "tokio", + "url", + "xmltree", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -3200,7 +3626,7 @@ dependencies = [ "futures-channel", "futures-util", "gloo-net", - "http", + "http 1.1.0", "jsonrpsee-core", "pin-project", "rustls", @@ -3225,8 +3651,8 @@ dependencies = [ "bytes", "futures-timer", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", "jsonrpsee-types", "parking_lot 0.12.3", @@ -3250,8 +3676,8 @@ checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" dependencies = [ "async-trait", "base64 0.22.1", - "http-body", - "hyper", + "http-body 1.0.1", + "hyper 1.4.1", "hyper-rustls", "hyper-util", "jsonrpsee-core", @@ -3287,10 +3713,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" dependencies = [ "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.4.1", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", @@ -3313,7 +3739,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" dependencies = [ - "http", + "http 1.1.0", "serde", "serde_json", "thiserror", @@ -3336,7 +3762,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" dependencies = [ - "http", + "http 1.1.0", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -3352,7 +3778,7 @@ dependencies = [ "base64 0.21.7", "js-sys", "pem", - "ring", + "ring 0.17.8", "serde", "serde_json", "simple_asn1", @@ -3418,7 +3844,7 @@ dependencies = [ "revm", "serde", "sha2 0.10.8", - "spin", + "spin 0.9.8", "tracing", "unsigned-varint 0.8.0", ] @@ -3439,7 +3865,7 @@ dependencies = [ "revm", "serde", "sha2 0.10.8", - "spin", + "spin 0.9.8", "superchain-primitives", "tracing", ] @@ -3498,7 +3924,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -3541,11 +3967,43 @@ dependencies = [ "futures-timer", "getrandom 0.2.15", "instant", - "libp2p-allow-block-list", - "libp2p-connection-limits", - "libp2p-core", + "libp2p-allow-block-list 0.3.0", + "libp2p-connection-limits 0.3.1", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm 0.44.2", + "multiaddr", + "pin-project", + "rw-stream-sink", + "thiserror", +] + +[[package]] +name = "libp2p" +version = "0.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbe80f9c7e00526cd6b838075b9c171919404a4732cb2fa8ece0a093223bfc4" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom 0.2.15", + "libp2p-allow-block-list 0.4.0", + "libp2p-connection-limits 0.4.0", + "libp2p-core 0.42.0", + "libp2p-dns", + "libp2p-gossipsub", "libp2p-identity", - "libp2p-swarm", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-noise", + "libp2p-ping", + "libp2p-quic", + "libp2p-swarm 0.45.1", + "libp2p-tcp", + "libp2p-upnp", + "libp2p-yamux", "multiaddr", "pin-project", "rw-stream-sink", @@ -3558,9 +4016,21 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" dependencies = [ - "libp2p-core", + "libp2p-core 0.41.3", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.44.2", + "void", +] + +[[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 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", "void", ] @@ -3570,9 +4040,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" dependencies = [ - "libp2p-core", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm 0.44.2", + "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 0.42.0", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.45.1", "void", ] @@ -3604,6 +4086,81 @@ dependencies = [ "web-time", ] +[[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 0.12.3", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "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 0.42.0", + "libp2p-identity", + "parking_lot 0.12.3", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4e830fdf24ac8c444c12415903174d506e1e077fbe3875c404a78c5935a8543" +dependencies = [ + "asynchronous-codec", + "base64 0.22.1", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-ticker", + "getrandom 0.2.15", + "hex_fmt", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.5", + "regex", + "sha2 0.10.8", + "smallvec", + "tracing", + "void", + "web-time", +] + [[package]] name = "libp2p-identity" version = "0.2.9" @@ -3624,6 +4181,112 @@ dependencies = [ "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 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "rand 0.8.5", + "smallvec", + "socket2 0.5.7", + "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 0.42.0", + "libp2p-gossipsub", + "libp2p-identity", + "libp2p-ping", + "libp2p-swarm 0.45.1", + "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 0.42.0", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand 0.8.5", + "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 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "rand 0.8.5", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-quic" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46352ac5cd040c70e88e7ff8257a2ae2f891a4076abad2c439584a31c15fd24e" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-tls", + "parking_lot 0.12.3", + "quinn", + "rand 0.8.5", + "ring 0.17.8", + "rustls", + "socket2 0.5.7", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "libp2p-swarm" version = "0.44.2" @@ -3635,15 +4298,118 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.41.3", + "libp2p-identity", + "lru", + "multistream-select", + "once_cell", + "rand 0.8.5", + "smallvec", + "tracing", + "void", +] + +[[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 0.42.0", "libp2p-identity", + "libp2p-swarm-derive", "lru", "multistream-select", "once_cell", "rand 0.8.5", "smallvec", + "tokio", "tracing", "void", + "web-time", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[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 0.42.0", + "libp2p-identity", + "socket2 0.5.7", + "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 0.42.0", + "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 0.42.0", + "libp2p-swarm 0.45.1", + "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 0.42.0", + "thiserror", + "tracing", + "yamux 0.12.1", + "yamux 0.13.3", ] [[package]] @@ -3931,7 +4697,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -4035,6 +4801,72 @@ dependencies = [ "tempfile", ] +[[package]] +name = "netlink-packet-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -4044,6 +4876,23 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -4159,7 +5008,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", ] @@ -4214,6 +5063,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.19.0" @@ -4269,7 +5127,17 @@ name = "op-net" version = "0.0.0" dependencies = [ "alloy", + "discv5", + "eyre", + "futures", "kona-primitives", + "lazy_static", + "libp2p 0.54.1", + "libp2p-identity", + "openssl", + "snap", + "tokio", + "tracing", ] [[package]] @@ -4324,6 +5192,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.3.1+3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.103" @@ -4332,6 +5209,7 @@ checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -4403,6 +5281,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.11.2" @@ -4555,6 +5439,32 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +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 0.5.1", +] + [[package]] name = "polyval" version = "0.5.3" @@ -4564,7 +5474,19 @@ dependencies = [ "cfg-if", "cpufeatures", "opaque-debug", - "universal-hash", + "universal-hash 0.4.0", +] + +[[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 0.5.1", ] [[package]] @@ -4667,6 +5589,29 @@ dependencies = [ "hex", ] +[[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 0.12.3", + "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.76", +] + [[package]] name = "proptest" version = "1.5.0" @@ -4717,6 +5662,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec", + "bytes", + "quick-protobuf", + "thiserror", + "unsigned-varint 0.8.0", +] + [[package]] name = "quinn" version = "0.11.3" @@ -4724,6 +5682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" dependencies = [ "bytes", + "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -4743,7 +5702,7 @@ checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.17.8", "rustc-hash 2.0.0", "rustls", "slab", @@ -4920,6 +5879,18 @@ dependencies = [ "crossbeam-utils", ] +[[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 = "recvmsg" version = "1.0.0" @@ -5010,11 +5981,11 @@ dependencies = [ "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.4.1", "hyper-rustls", "hyper-tls", "hyper-util", @@ -5035,7 +6006,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-rustls", @@ -6453,7 +7424,7 @@ version = "1.0.5" source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "eyre", - "http", + "http 1.1.0", "jsonrpsee", "metrics", "metrics-exporter-prometheus", @@ -6725,9 +7696,9 @@ dependencies = [ "async-trait", "derive_more 1.0.0", "futures", - "http", - "http-body", - "hyper", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", "jsonrpsee", "jsonwebtoken", "parking_lot 0.12.3", @@ -6787,7 +7758,7 @@ name = "reth-rpc-builder" version = "1.0.5" source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ - "http", + "http 1.1.0", "jsonrpsee", "metrics", "pin-project", @@ -6923,7 +7894,7 @@ version = "1.0.5" source = "git+https://github.com/paradigmxyz/reth#498ced8be9d1340a9a79f2dbd84e676dc2381888" dependencies = [ "alloy-rpc-types-engine", - "http", + "http 1.1.0", "jsonrpsee-http-client", "pin-project", "tower", @@ -7368,6 +8339,21 @@ dependencies = [ "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" @@ -7378,8 +8364,8 @@ dependencies = [ "cfg-if", "getrandom 0.2.15", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -7463,6 +8449,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +[[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" @@ -7535,6 +8536,15 @@ 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.34" @@ -7556,9 +8566,9 @@ checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "log", "once_cell", - "ring", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.6", "subtle", "zeroize", ] @@ -7606,7 +8616,7 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki", + "rustls-webpki 0.102.6", "security-framework", "security-framework-sys", "webpki-roots", @@ -7619,15 +8629,25 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[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.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -8107,6 +9127,23 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm 0.10.3", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core 0.6.4", + "ring 0.17.8", + "rustc_version 0.4.0", + "sha2 0.10.8", + "subtle", +] + [[package]] name = "socket2" version = "0.4.10" @@ -8136,13 +9173,19 @@ dependencies = [ "base64 0.22.1", "bytes", "futures", - "http", + "http 1.1.0", "httparse", "log", "rand 0.8.5", "sha1", ] +[[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" @@ -8308,6 +9351,17 @@ dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + [[package]] name = "sysinfo" version = "0.30.13" @@ -8322,6 +9376,17 @@ dependencies = [ "windows 0.52.0", ] +[[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" @@ -8330,7 +9395,17 @@ checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "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]] @@ -8680,8 +9755,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", "http-range-header", "httpdate", @@ -8892,7 +9967,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 1.1.0", "httparse", "log", "rand 0.8.5", @@ -9002,6 +10077,16 @@ dependencies = [ "subtle", ] +[[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 = "unsafe-libyaml" version = "0.2.11" @@ -9020,6 +10105,12 @@ 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" @@ -9269,6 +10360,16 @@ 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" version = "0.52.0" @@ -9289,6 +10390,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[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" @@ -9584,6 +10694,90 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" + +[[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 0.12.3", + "pin-project", + "rand 0.8.5", + "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 0.12.3", + "pin-project", + "rand 0.8.5", + "static_assertions", + "web-time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 51ec209..b858b2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -153,10 +153,19 @@ reth-revm = { git = "https://github.com/paradigmxyz/reth", version = "1.0.5" } reth-evm = { git = "https://github.com/paradigmxyz/reth", version = "1.0.5" } reth-tracing = { git = "https://github.com/paradigmxyz/reth", version = "1.0.5" } +# Networking +snap = "1.1.1" +discv5 = "0.6.0" +openssl = { version = "0.10.66", features = ["vendored"] } +libp2p-identity = { version = "0.2.9", features = [ "secp256k1" ] } +libp2p = { version = "0.54.0", features = ["macros", "tokio", "tcp", "noise", "gossipsub", "ping", "yamux"] } + # Misc tracing = "0.1.0" eyre = "0.6.12" clap = "4" +lazy_static = "1.5.0" +futures = "0.3.30" async-trait = "0.1.81" hashbrown = "0.14.5" parking_lot = "0.12.3" diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml index 3dc575c..ad24901 100644 --- a/crates/net/Cargo.toml +++ b/crates/net/Cargo.toml @@ -11,5 +11,22 @@ categories.workspace = true rust-version.workspace = true [dependencies] +# Alloy alloy.workspace = true + +# Kona kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } + +# Networking +snap.workspace = true +futures.workspace = true +discv5.workspace = true +libp2p.workspace = true +openssl.workspace = true +libp2p-identity.workspace = true + +# Misc +eyre.workspace = true +tokio.workspace = true +tracing.workspace = true +lazy_static.workspace = true diff --git a/crates/net/src/behaviour.rs b/crates/net/src/behaviour.rs new file mode 100644 index 0000000..5ff6bad --- /dev/null +++ b/crates/net/src/behaviour.rs @@ -0,0 +1,46 @@ +//! Network Behaviour Module. + +use eyre::Result; +use libp2p::{ + gossipsub::{Config, IdentTopic, MessageAuthenticity}, + swarm::NetworkBehaviour, +}; + +use crate::{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. + ping: libp2p::ping::Behaviour, + /// Enables gossipsub as the routing layer. + 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 }) + } +} diff --git a/crates/net/src/builder.rs b/crates/net/src/builder.rs new file mode 100644 index 0000000..f3da0f7 --- /dev/null +++ b/crates/net/src/builder.rs @@ -0,0 +1,91 @@ +//! Network Builder Module. + +use alloy::primitives::Address; +use eyre::Result; +use libp2p::gossipsub::ConfigBuilder; +use libp2p_identity::Keypair; +use std::net::SocketAddr; +use tokio::sync::watch::channel; + +use crate::{behaviour::Behaviour, config, driver::GossipDriver, handler::BlockHandler}; + +/// Constructs a [GossipDriver] for the OP Stack P2P network. +#[derive(Default)] +pub struct GossipDriverBuilder { + /// The chain ID of the network. + chain_id: Option, + /// The unsafe block signer. + unsafe_block_signer: Option
, + /// The socket address that the service is listening on. + socket: Option, + /// The [ConfigBuilder] constructs the [Config] for `gossipsub`. + inner: Option, + /// The [Keypair] for the node. + keypair: Option, +} + +impl GossipDriverBuilder { + /// Creates a new [GossipDriverBuilder]. + 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 socket address that the service is listening on. + pub fn with_socket(&mut self, socket: SocketAddr) -> &mut Self { + self.socket = Some(socket); + self + } + + /// Specifies the keypair for the node. + pub fn with_keypair(&mut self, keypair: Keypair) -> &mut Self { + self.keypair = Some(keypair); + self + } + + // TODO: extend builder with [ConfigBuilder] methods. + + /// Specifies the [ConfigBuilder] for the `gossipsub` configuration. + pub fn with_gossip_config(&mut self, inner: ConfigBuilder) -> &mut Self { + self.inner = Some(inner); + self + } + + /// Builds the [GossipDriver]. + pub fn build(self) -> Result { + // Build the config for gossipsub. + let config = self.inner.unwrap_or(config::default_config_builder()).build()?; + 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 (block_handler, unsafe_block_recv) = + BlockHandler::new(chain_id, unsafe_block_signer_recv); + + // Construct the gossipsub behaviour. + let behaviour = Behaviour::new(config, &[Box::new(block_handler.clone())])?; + + Ok(GossipDriver { + behaviour, + unsafe_block_recv, + unsafe_block_signer_sender, + chain_id, + handler: block_handler, + addr: self.socket.ok_or_else(|| eyre::eyre!("socket address not set"))?, + keypair: self.keypair.unwrap_or(Keypair::generate_secp256k1()), + }) + } +} diff --git a/crates/net/src/config.rs b/crates/net/src/config.rs new file mode 100644 index 0000000..4d2a2f9 --- /dev/null +++ b/crates/net/src/config.rs @@ -0,0 +1,112 @@ +//! Gossipsub Configuration + +use lazy_static::lazy_static; +use libp2p::gossipsub::{ConfigBuilder, 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 +/// - 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 +} + +/// 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/driver.rs b/crates/net/src/driver.rs new file mode 100644 index 0000000..70d3a68 --- /dev/null +++ b/crates/net/src/driver.rs @@ -0,0 +1,88 @@ +//! Driver for p2p services. + +use alloy::primitives::Address; +use eyre::Result; +use futures::stream::StreamExt; +use libp2p::{swarm::SwarmEvent, Multiaddr, SwarmBuilder}; +use libp2p_identity::Keypair; +use std::net::SocketAddr; +use tokio::{ + select, + sync::watch::{Receiver, Sender}, +}; + +use crate::{ + behaviour::Behaviour, + event::Event, + handler::{BlockHandler, Handler}, + types::{ExecutionPayloadEnvelope, NetworkAddress}, +}; + +/// Driver contains the logic for the P2P service. +pub struct GossipDriver { + /// The [Behaviour] of the node. + pub behaviour: Behaviour, + /// Channel to receive unsafe blocks. + pub unsafe_block_recv: Receiver, + /// Channel to send unsafe signer updates. + pub unsafe_block_signer_sender: Sender
, + /// The socket address that the service is listening on. + pub addr: SocketAddr, + /// Block handler. + pub handler: BlockHandler, + /// The chain ID of the network. + pub chain_id: u64, + /// A unique keypair to validate the node's identity + pub keypair: Keypair, +} + +impl GossipDriver { + /// Starts the Discv5 peer discovery & libp2p services + /// and continually listens for new peers and messages to handle + pub fn start(self) -> Result<()> { + // TODO: pull this swarm building out into the builder + let mut swarm = SwarmBuilder::with_existing_identity(self.keypair.clone()) + .with_tokio() + .with_tcp( + libp2p::tcp::Config::default(), + libp2p::noise::Config::new, + libp2p::yamux::Config::default, + )? + .with_behaviour(|_| self.behaviour)? + .build(); + let addr = NetworkAddress::try_from(self.addr)?; + // let mut peer_recv = discovery::start(addr, self.chain_id)?; + let multiaddr = Multiaddr::from(addr); + swarm.listen_on(multiaddr).map_err(|_| eyre::eyre!("swarm listen failed"))?; + let handler = self.handler.clone(); + tokio::spawn(async move { + loop { + select! { + // peer = peer_recv.recv().fuse() => { + // if let Some(peer) = peer { + // let peer = Multiaddr::from(peer); + // _ = swarm.dial(peer); + // } + // }, + event = swarm.select_next_some() => { + if let SwarmEvent::Behaviour(Event::Gossipsub(libp2p::gossipsub::Event::Message { + propagation_source: _peer_id, + message_id: _id, + message, + })) = event { + if handler.topics().contains(&message.topic) { + let _status = handler.handle(message); + // TODO: report message validation result?? + // _ = swarm + // .behaviour_mut() + // .report_message_validation_result(&message_id, &propagation_source, status); + } + } + }, + } + } + }); + + Ok(()) + } +} diff --git a/crates/net/src/event.rs b/crates/net/src/event.rs new file mode 100644 index 0000000..0175130 --- /dev/null +++ b/crates/net/src/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/handler.rs b/crates/net/src/handler.rs new file mode 100644 index 0000000..c90640f --- /dev/null +++ b/crates/net/src/handler.rs @@ -0,0 +1,124 @@ +#![allow(unused)] +//! Block Handler + +use alloy::primitives::Address; +use libp2p::gossipsub::{IdentTopic, Message, MessageAcceptance, TopicHash}; +use std::time::SystemTime; +use tokio::sync::watch::{channel, Receiver, Sender}; +// use ssz_rs::{prelude::*, List, Vector, U256}; + +use crate::types::ExecutionPayloadEnvelope; + +/// 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. + chain_id: u64, + /// A channel sender to forward new blocks to other modules + block_sender: Sender, + /// A [watch::Receiver] to monitor changes to the unsafe block signer. + unsafe_signer_recv: Receiver
, + /// The libp2p topic for pre Canyon/Shangai blocks. + blocks_v1_topic: IdentTopic, + /// The libp2p topic for Canyon/Delta blocks. + blocks_v2_topic: IdentTopic, + /// The libp2p topic for Ecotone V3 blocks. + 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"); + + if msg.topic == self.blocks_v1_topic.hash() { + // decode_pre_ecotone_block_msg::(msg.data) + unimplemented!() + } else if msg.topic == self.blocks_v2_topic.hash() { + // decode_pre_ecotone_block_msg::(msg.data) + unimplemented!() + } else if msg.topic == self.blocks_v3_topic.hash() { + // decode_post_ecotone_block_msg(msg.data) + unimplemented!() + } 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()] + } +} + +impl BlockHandler { + /// Creates a new [BlockHandler] and opens a channel + pub fn new( + chain_id: u64, + unsafe_recv: Receiver
, + ) -> (Self, Receiver) { + let (sender, recv) = channel(ExecutionPayloadEnvelope::default()); + + 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: &ExecutionPayloadEnvelope) -> 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.hash.signature_message(self.chain_id); + let block_signer = *self.unsafe_signer_recv.borrow(); + let Ok(msg_signer) = envelope.signature.recover_address_from_msg(msg) else { + // TODO: add telemetry here if this happens. + return false; + }; + + time_valid && msg_signer == block_signer + } +} diff --git a/crates/net/src/lib.rs b/crates/net/src/lib.rs index 86aa2df..d1f2c03 100644 --- a/crates/net/src/lib.rs +++ b/crates/net/src/lib.rs @@ -3,8 +3,11 @@ #![doc(issue_tracker_base_url = "https://github.com/paradigmxyz/op-rs/issues/")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -#![cfg_attr(not(test), no_std)] - -extern crate alloc; +pub mod behaviour; +pub mod builder; +pub mod config; +pub mod driver; +pub mod event; +pub mod handler; pub mod types; diff --git a/crates/net/src/types.rs b/crates/net/src/types.rs index e7f939a..44e01e2 100644 --- a/crates/net/src/types.rs +++ b/crates/net/src/types.rs @@ -1,11 +1,17 @@ //! Types for the P2P network. -use alloc::vec::Vec; use alloy::primitives::{keccak256, Signature, B256}; +use discv5::enr::{CombinedKey, Enr}; +use eyre::Result; use kona_primitives::L2ExecutionPayload; +use libp2p::{multiaddr::Protocol, Multiaddr}; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + str::FromStr, +}; /// An envelope around the execution payload for L2. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ExecutionPayloadEnvelope { /// The execution payload. pub payload: L2ExecutionPayload, @@ -17,8 +23,22 @@ pub struct ExecutionPayloadEnvelope { pub parent_beacon_block_root: Option, } +impl Default for ExecutionPayloadEnvelope { + fn default() -> Self { + Self { + payload: L2ExecutionPayload::default(), + // Generic signature taken from `alloy_primitives` tests. + // + // https://github.com/alloy-rs/core/blob/main/crates/primitives/src/signature/sig.rs#L614 + signature: Signature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap(), + hash: PayloadHash::default(), + parent_beacon_block_root: None, + } + } +} + /// Represents the Keccak256 hash of the block -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub struct PayloadHash(B256); impl From<&[u8]> for PayloadHash { @@ -31,14 +51,87 @@ impl From<&[u8]> for PayloadHash { impl PayloadHash { /// The expected message that should be signed by the unsafe block signer. pub fn signature_message(&self, chain_id: u64) -> B256 { - let domain = B256::ZERO; + let domain = B256::ZERO.as_slice(); let chain_id = B256::left_padding_from(&chain_id.to_be_bytes()[..]); - let payload_hash = self.0; + let payload_hash = self.0.as_slice(); + keccak256([domain, chain_id.as_slice(), payload_hash].concat()) + } +} + +/// An [Ipv4Addr] and port. +#[derive(Debug, Clone, Copy)] +pub struct NetworkAddress { + /// An [Ipv4Addr] + pub ip: Ipv4Addr, + /// A port + pub port: u16, +} + +/// A wrapper around a peer's Network Address. +#[derive(Debug)] +pub struct Peer { + /// The peer's [Ipv4Addr] and port + pub addr: NetworkAddress, +} + +impl TryFrom<&Enr> for NetworkAddress { + type Error = eyre::Report; + + /// Convert an [Enr] to a Network Address. + 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"))?; + + Ok(Self { ip, port }) + } +} - let data: Vec = - [domain.as_slice(), chain_id.as_slice(), payload_hash.as_slice()].concat(); +impl From for Multiaddr { + /// Converts a Network Address to a [Multiaddr] + fn from(value: NetworkAddress) -> Self { + let mut multiaddr = Multiaddr::empty(); + multiaddr.push(Protocol::Ip4(value.ip)); + multiaddr.push(Protocol::Tcp(value.port)); + + multiaddr + } +} + +impl From for SocketAddr { + /// Converts a Network Address to a [SocketAddr]. + fn from(value: NetworkAddress) -> Self { + SocketAddr::new(IpAddr::V4(value.ip), value.port) + } +} + +impl TryFrom for NetworkAddress { + type Error = eyre::Report; + + /// Converts a [SocketAddr] to a Network Address. + fn try_from(value: SocketAddr) -> Result { + let ip = match value.ip() { + IpAddr::V4(ip) => ip, + IpAddr::V6(_) => eyre::bail!("ipv6 not supported"), + }; + + Ok(Self { ip, port: value.port() }) + } +} + +impl TryFrom<&Enr> for Peer { + type Error = eyre::Report; + + /// Converts an [Enr] to a Peer + fn try_from(value: &Enr) -> Result { + let addr = NetworkAddress::try_from(value)?; + Ok(Peer { addr }) + } +} - keccak256(data) +impl From for Multiaddr { + /// Converts a Peer to a [Multiaddr] + fn from(value: Peer) -> Self { + value.addr.into() } } From db59de438a2875e23511df9b0cee61eac40b33db Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 16:52:08 -0400 Subject: [PATCH 03/16] fix(net): doc lints --- crates/net/src/builder.rs | 2 +- crates/net/src/handler.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/net/src/builder.rs b/crates/net/src/builder.rs index f3da0f7..610eca9 100644 --- a/crates/net/src/builder.rs +++ b/crates/net/src/builder.rs @@ -18,7 +18,7 @@ pub struct GossipDriverBuilder { unsafe_block_signer: Option
, /// The socket address that the service is listening on. socket: Option, - /// The [ConfigBuilder] constructs the [Config] for `gossipsub`. + /// The [ConfigBuilder] constructs the config for `gossipsub`. inner: Option, /// The [Keypair] for the node. keypair: Option, diff --git a/crates/net/src/handler.rs b/crates/net/src/handler.rs index c90640f..7cb58ca 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/handler.rs @@ -28,7 +28,7 @@ pub struct BlockHandler { chain_id: u64, /// A channel sender to forward new blocks to other modules block_sender: Sender, - /// A [watch::Receiver] to monitor changes to the unsafe block signer. + /// A [Receiver] to monitor changes to the unsafe block signer. unsafe_signer_recv: Receiver
, /// The libp2p topic for pre Canyon/Shangai blocks. blocks_v1_topic: IdentTopic, From 1a8dcea83e5212906bb5e406274d44cb30b75667 Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 19:06:33 -0400 Subject: [PATCH 04/16] feat(net): discovery --- Cargo.lock | 2 + Cargo.toml | 1 + crates/net/Cargo.toml | 2 + crates/net/src/bootnodes.rs | 22 ++++++ crates/net/src/discovery.rs | 135 ++++++++++++++++++++++++++++++++++++ crates/net/src/lib.rs | 3 + crates/net/src/op_enr.rs | 65 +++++++++++++++++ 7 files changed, 230 insertions(+) create mode 100644 crates/net/src/bootnodes.rs create mode 100644 crates/net/src/discovery.rs create mode 100644 crates/net/src/op_enr.rs diff --git a/Cargo.lock b/Cargo.lock index ef603e9..923fd68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5127,6 +5127,7 @@ name = "op-net" version = "0.0.0" dependencies = [ "alloy", + "alloy-rlp", "discv5", "eyre", "futures", @@ -5138,6 +5139,7 @@ dependencies = [ "snap", "tokio", "tracing", + "unsigned-varint 0.8.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b858b2d..73a7abc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -169,5 +169,6 @@ futures = "0.3.30" async-trait = "0.1.81" hashbrown = "0.14.5" parking_lot = "0.12.3" +unsigned-varint = "0.8.0" rand = { version = "0.8.3", features = ["small_rng"], default-features = false } url = "2.5.2" diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml index ad24901..6e29d72 100644 --- a/crates/net/Cargo.toml +++ b/crates/net/Cargo.toml @@ -13,6 +13,7 @@ rust-version.workspace = true [dependencies] # Alloy alloy.workspace = true +alloy-rlp.workspace = true # Kona kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } @@ -30,3 +31,4 @@ eyre.workspace = true tokio.workspace = true tracing.workspace = true lazy_static.workspace = true +unsigned-varint.workspace = true diff --git a/crates/net/src/bootnodes.rs b/crates/net/src/bootnodes.rs new file mode 100644 index 0000000..9e20aaa --- /dev/null +++ b/crates/net/src/bootnodes.rs @@ -0,0 +1,22 @@ +//! 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(), + ].to_vec(); +} diff --git a/crates/net/src/discovery.rs b/crates/net/src/discovery.rs new file mode 100644 index 0000000..4919fe0 --- /dev/null +++ b/crates/net/src/discovery.rs @@ -0,0 +1,135 @@ +//! Discovery Module. + +use eyre::Result; +use std::time::Duration; +use tokio::{ + sync::mpsc::{channel, Receiver}, + time::sleep, +}; +use tracing::{trace, warn}; + +use discv5::{ + enr::{CombinedKey, Enr, NodeId}, + ConfigBuilder, Discv5, ListenConfig, +}; + +use crate::{ + bootnodes::BOOTNODES, + op_enr::OpStackEnr, + types::{NetworkAddress, Peer}, +}; + +/// The number of peers to buffer in the channel. +const DISCOVERY_PEER_CHANNEL_SIZE: usize = 256; + +/// 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, +} + +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: NetworkAddress) -> 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 + } + + /// Generates an [Enr] and creates a [Discv5] service struct + fn create_disc(&self) -> Result { + let addr = self.address.ok_or_else(|| eyre::eyre!("address not set"))?; + let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; + let opstack = OpStackEnr::new(chain_id, 0); + let opstack_data: Vec = opstack.into(); + + let key = CombinedKey::generate_secp256k1(); + let enr = Enr::builder().add_value_rlp("opstack", opstack_data.into()).build(&key)?; + let listen_config = ListenConfig::from_ip(addr.ip.into(), addr.port); + let config = ConfigBuilder::new(listen_config).build(); + + Discv5::new(enr, key, config).map_err(|_| eyre::eyre!("could not create disc service")) + } + + /// 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 [DiscoveryBuilder]. + /// + /// ## Example + /// + /// ```no_run + /// use op_net::discovery::DiscoveryBuilder; + /// + /// let builder = DiscoveryBuilder::new() + /// .with_address("") + /// .with_chain_id(10) // OP Mainnet chain id + /// .start() + /// .expect("Failed to start discovery service"); + /// + /// loop { + /// if let Some(peer) = builder.recv().await { + /// println!("Received peer: {:?}", peer); + /// } + /// ``` + pub fn start(self) -> Result> { + let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; + + // Clone the bootnodes since the spawned thread takes mutable ownership. + let bootnodes = BOOTNODES.clone(); + + // Construct the discovery service. + let mut disc = self.create_disc()?; + + // 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| _ = disc.add_enr(enr)); + disc.start().await.unwrap(); + + trace!("Started peer discovery"); + + loop { + let target = NodeId::random(); + match disc.find_node(target).await { + Ok(nodes) => { + let peers = nodes + .iter() + .filter(|node| OpStackEnr::is_valid_node(node, chain_id)) + .flat_map(Peer::try_from); + + for peer in peers { + _ = sender.send(peer).await; + } + } + Err(err) => { + warn!("discovery error: {:?}", err); + } + } + + sleep(Duration::from_secs(10)).await; + } + }); + + Ok(recv) + } +} diff --git a/crates/net/src/lib.rs b/crates/net/src/lib.rs index d1f2c03..44276eb 100644 --- a/crates/net/src/lib.rs +++ b/crates/net/src/lib.rs @@ -5,9 +5,12 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] pub mod behaviour; +pub mod bootnodes; pub mod builder; pub mod config; +pub mod discovery; pub mod driver; pub mod event; pub mod handler; +pub mod op_enr; pub mod types; diff --git a/crates/net/src/op_enr.rs b/crates/net/src/op_enr.rs new file mode 100644 index 0000000..ad306ea --- /dev/null +++ b/crates/net/src/op_enr.rs @@ -0,0 +1,65 @@ +//! Contains the OP Stack Enr Type. + +use discv5::enr::{CombinedKey, Enr}; +use eyre::Result; +use unsigned_varint::{decode, encode}; + +/// The unique L2 network identifier +#[derive(Debug, Clone, Copy, Default)] +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("opstack") + .map(|opstack| { + OpStackEnr::try_from(opstack) + .map(|opstack| opstack.chain_id == chain_id && opstack.version == 0) + .unwrap_or_default() + }) + .unwrap_or_default() + } +} + +impl TryFrom<&[u8]> for OpStackEnr { + type Error = eyre::Report; + + /// Converts a slice of RLP encoded bytes to Op Stack Enr Data. + fn try_from(value: &[u8]) -> Result { + // TODO: rlp decode first? + // let bytes = Vec::::decode(&mut value)?; + let mut bytes = value; + let (chain_id, rest) = + decode::u64(bytes).map_err(|_| eyre::eyre!("could not decode chain id"))?; + bytes = rest; + let (version, _) = + decode::u64(bytes).map_err(|_| eyre::eyre!("could not decode chain id"))?; + + Ok(Self { chain_id, version }) + } +} + +impl From for Vec { + /// Converts Op Stack Enr data to a vector of bytes. + fn from(value: OpStackEnr) -> Vec { + let mut chain_id_buf = encode::u128_buffer(); + let chain_id_slice = encode::u128(value.chain_id as u128, &mut chain_id_buf); + + let mut version_buf = encode::u128_buffer(); + let version_slice = encode::u128(value.version as u128, &mut version_buf); + + let opstack = [chain_id_slice, version_slice].concat(); + + alloy_rlp::encode(&opstack).to_vec() + } +} From 200fa0a05f84148b88dce74ab2f5cc0b94abac56 Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 19:09:09 -0400 Subject: [PATCH 05/16] feat(net): start discovery in driver --- crates/net/src/driver.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/net/src/driver.rs b/crates/net/src/driver.rs index 70d3a68..44e4a13 100644 --- a/crates/net/src/driver.rs +++ b/crates/net/src/driver.rs @@ -13,6 +13,7 @@ use tokio::{ use crate::{ behaviour::Behaviour, + discovery::DiscoveryBuilder, event::Event, handler::{BlockHandler, Handler}, types::{ExecutionPayloadEnvelope, NetworkAddress}, @@ -51,19 +52,20 @@ impl GossipDriver { .with_behaviour(|_| self.behaviour)? .build(); let addr = NetworkAddress::try_from(self.addr)?; - // let mut peer_recv = discovery::start(addr, self.chain_id)?; + let mut peer_recv = + DiscoveryBuilder::new().with_address(addr).with_chain_id(self.chain_id).start()?; let multiaddr = Multiaddr::from(addr); swarm.listen_on(multiaddr).map_err(|_| eyre::eyre!("swarm listen failed"))?; let handler = self.handler.clone(); tokio::spawn(async move { loop { select! { - // peer = peer_recv.recv().fuse() => { - // if let Some(peer) = peer { - // let peer = Multiaddr::from(peer); - // _ = swarm.dial(peer); - // } - // }, + peer = peer_recv.recv() => { + if let Some(peer) = peer { + let peer = Multiaddr::from(peer); + _ = swarm.dial(peer); + } + }, event = swarm.select_next_some() => { if let SwarmEvent::Behaviour(Event::Gossipsub(libp2p::gossipsub::Event::Message { propagation_source: _peer_id, From d06b46026d712ee9940bffecf524187a0931d3e6 Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 20:23:17 -0400 Subject: [PATCH 06/16] feat(net): acknowledgement --- crates/net/README.md | 7 +++++++ crates/net/src/discovery.rs | 24 +++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 crates/net/README.md diff --git a/crates/net/README.md b/crates/net/README.md new file mode 100644 index 0000000..f2c6ebc --- /dev/null +++ b/crates/net/README.md @@ -0,0 +1,7 @@ +## Network Library + +Contains a gossipsub driver to run discv5 peer discovery and block gossip. + +## Acknowledgements + +Largely based off [magi][https://github.com/a16z/magi]'s [p2p module](https://github.com/a16z/magi/tree/master/src/network). diff --git a/crates/net/src/discovery.rs b/crates/net/src/discovery.rs index 4919fe0..910ec1e 100644 --- a/crates/net/src/discovery.rs +++ b/crates/net/src/discovery.rs @@ -76,17 +76,23 @@ impl DiscoveryBuilder { /// ## Example /// /// ```no_run - /// use op_net::discovery::DiscoveryBuilder; + /// use op_net::{discovery::DiscoveryBuilder, types::NetworkAddress}; + /// use std::net::Ipv4Addr; /// - /// let builder = DiscoveryBuilder::new() - /// .with_address("") - /// .with_chain_id(10) // OP Mainnet chain id - /// .start() - /// .expect("Failed to start discovery service"); + /// #[tokio::main] + /// async fn main() { + /// let network_addr = NetworkAddress { ip: Ipv4Addr::new(127, 0, 0, 1), port: 9000 }; + /// let mut peer_recv = DiscoveryBuilder::new() + /// .with_address(network_addr) + /// .with_chain_id(10) // OP Mainnet chain id + /// .start() + /// .expect("Failed to start discovery service"); /// - /// loop { - /// if let Some(peer) = builder.recv().await { - /// println!("Received peer: {:?}", peer); + /// loop { + /// if let Some(peer) = peer_recv.recv().await { + /// println!("Received peer: {:?}", peer); + /// } + /// } /// } /// ``` pub fn start(self) -> Result> { From 2198d321c0408ea6c0a96477a5c7543280103f34 Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 20:47:48 -0400 Subject: [PATCH 07/16] fix(net): make gosipsub field public on behaviour --- crates/net/src/behaviour.rs | 31 +++++++++++++++++++++++++++++-- crates/net/src/driver.rs | 16 ++++++++-------- crates/net/src/handler.rs | 12 ++++++------ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/crates/net/src/behaviour.rs b/crates/net/src/behaviour.rs index 5ff6bad..862691e 100644 --- a/crates/net/src/behaviour.rs +++ b/crates/net/src/behaviour.rs @@ -13,9 +13,9 @@ use crate::{event::Event, handler::Handler}; #[behaviour(out_event = "Event")] pub struct Behaviour { /// Responds to inbound pings and send outbound pings. - ping: libp2p::ping::Behaviour, + pub ping: libp2p::ping::Behaviour, /// Enables gossipsub as the routing layer. - gossipsub: libp2p::gossipsub::Behaviour, + pub gossipsub: libp2p::gossipsub::Behaviour, } impl Behaviour { @@ -44,3 +44,30 @@ impl Behaviour { Ok(Self { ping, gossipsub }) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::handler::BlockHandler; + use alloy::primitives::Address; + + #[test] + fn test_behaviour_no_handlers() { + let cfg = crate::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 = crate::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::new(cfg, &handlers).unwrap(); + } +} diff --git a/crates/net/src/driver.rs b/crates/net/src/driver.rs index 44e4a13..5b22932 100644 --- a/crates/net/src/driver.rs +++ b/crates/net/src/driver.rs @@ -1,4 +1,4 @@ -//! Driver for p2p services. +//! Driver for network services. use alloy::primitives::Address; use eyre::Result; @@ -68,16 +68,16 @@ impl GossipDriver { }, event = swarm.select_next_some() => { if let SwarmEvent::Behaviour(Event::Gossipsub(libp2p::gossipsub::Event::Message { - propagation_source: _peer_id, - message_id: _id, + propagation_source: src, + message_id: id, message, })) = event { if handler.topics().contains(&message.topic) { - let _status = handler.handle(message); - // TODO: report message validation result?? - // _ = swarm - // .behaviour_mut() - // .report_message_validation_result(&message_id, &propagation_source, status); + let status = handler.handle(message); + _ = swarm + .behaviour_mut() + .gossipsub + .report_message_validation_result(&id, &src, status); } } }, diff --git a/crates/net/src/handler.rs b/crates/net/src/handler.rs index 7cb58ca..434fa49 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/handler.rs @@ -25,17 +25,17 @@ pub trait Handler: Send { pub struct BlockHandler { /// Chain ID of the L2 blockchain. Used to filter out gossip messages intended for other /// blockchains. - chain_id: u64, + pub chain_id: u64, /// A channel sender to forward new blocks to other modules - block_sender: Sender, + pub block_sender: Sender, /// A [Receiver] to monitor changes to the unsafe block signer. - unsafe_signer_recv: Receiver
, + pub unsafe_signer_recv: Receiver
, /// The libp2p topic for pre Canyon/Shangai blocks. - blocks_v1_topic: IdentTopic, + pub blocks_v1_topic: IdentTopic, /// The libp2p topic for Canyon/Delta blocks. - blocks_v2_topic: IdentTopic, + pub blocks_v2_topic: IdentTopic, /// The libp2p topic for Ecotone V3 blocks. - blocks_v3_topic: IdentTopic, + pub blocks_v3_topic: IdentTopic, } impl Handler for BlockHandler { From a91bc6dfddf79b3d66993283259eb88c7be3556b Mon Sep 17 00:00:00 2001 From: refcell Date: Sun, 25 Aug 2024 20:59:07 -0400 Subject: [PATCH 08/16] fix(net): add behaviour tests --- crates/net/src/behaviour.rs | 14 +++++++++++++- crates/net/src/handler.rs | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/net/src/behaviour.rs b/crates/net/src/behaviour.rs index 862691e..861e543 100644 --- a/crates/net/src/behaviour.rs +++ b/crates/net/src/behaviour.rs @@ -50,6 +50,15 @@ mod tests { use super::*; use crate::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() { @@ -68,6 +77,9 @@ mod tests { 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::new(cfg, &handlers).unwrap(); + 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/handler.rs b/crates/net/src/handler.rs index 434fa49..ea2c340 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/handler.rs @@ -76,7 +76,7 @@ impl Handler for BlockHandler { /// The gossip topics accepted for new blocks fn topics(&self) -> Vec { - vec![self.blocks_v1_topic.hash(), self.blocks_v2_topic.hash()] + vec![self.blocks_v1_topic.hash(), self.blocks_v2_topic.hash(), self.blocks_v3_topic.hash()] } } From 6ca318b9a6b287bb885da5914c4ccfd14b5a1221 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 13:23:41 -0400 Subject: [PATCH 09/16] fix(net): refactor swarm builder out of driver --- Cargo.lock | 26 ++++ Cargo.toml | 3 + crates/net/Cargo.toml | 1 + crates/net/src/builder.rs | 82 +++++++++--- crates/net/src/discovery.rs | 46 ++++--- crates/net/src/driver.rs | 65 ++++------ crates/net/src/handler.rs | 47 ++++--- crates/net/src/lib.rs | 2 + crates/net/src/op_enr.rs | 7 +- crates/net/src/ssz.rs | 245 ++++++++++++++++++++++++++++++++++++ crates/net/src/swarm.rs | 43 +++++++ crates/net/src/types.rs | 59 +++++++++ 12 files changed, 525 insertions(+), 101 deletions(-) create mode 100644 crates/net/src/ssz.rs create mode 100644 crates/net/src/swarm.rs diff --git a/Cargo.lock b/Cargo.lock index 923fd68..9e33c62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5137,6 +5137,7 @@ dependencies = [ "libp2p-identity", "openssl", "snap", + "ssz_rs", "tokio", "tracing", "unsigned-varint 0.8.0", @@ -9207,6 +9208,31 @@ dependencies = [ "der", ] +[[package]] +name = "ssz_rs" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057291e5631f280978fa9c8009390663ca4613359fc1318e36a8c24c392f6d1f" +dependencies = [ + "bitvec", + "hex", + "num-bigint", + "serde", + "sha2 0.9.9", + "ssz_rs_derive", +] + +[[package]] +name = "ssz_rs_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "stability" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 73a7abc..31ca407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,6 +137,9 @@ alloy-rlp = "0.3.4" # Tokio tokio = { version = "1.21", default-features = false } +# SSZ +ssz_rs = "0.9.0" + # Reth reth = { git = "https://github.com/paradigmxyz/reth", version = "1.0.5" } reth-chainspec = { git = "https://github.com/paradigmxyz/reth", version = "1.0.5" } diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml index 6e29d72..1867fb3 100644 --- a/crates/net/Cargo.toml +++ b/crates/net/Cargo.toml @@ -19,6 +19,7 @@ alloy-rlp.workspace = true kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } # Networking +ssz_rs.workspace = true snap.workspace = true futures.workspace = true discv5.workspace = true diff --git a/crates/net/src/builder.rs b/crates/net/src/builder.rs index 610eca9..c126ad8 100644 --- a/crates/net/src/builder.rs +++ b/crates/net/src/builder.rs @@ -2,16 +2,23 @@ use alloy::primitives::Address; use eyre::Result; -use libp2p::gossipsub::ConfigBuilder; -use libp2p_identity::Keypair; use std::net::SocketAddr; use tokio::sync::watch::channel; -use crate::{behaviour::Behaviour, config, driver::GossipDriver, handler::BlockHandler}; +use libp2p::{ + gossipsub::ConfigBuilder, noise::Config as NoiseConfig, tcp::Config as TcpConfig, + yamux::Config as YamuxConfig, Multiaddr, SwarmBuilder, +}; +use libp2p_identity::Keypair; + +use crate::{ + behaviour::Behaviour, config, discovery::DiscoveryBuilder, driver::NetworkDriver, + handler::BlockHandler, swarm::SwarmDriver, types::NetworkAddress, +}; -/// Constructs a [GossipDriver] for the OP Stack P2P network. +/// Constructs a [NetworkDriver] for Optimism's consensus-layer. #[derive(Default)] -pub struct GossipDriverBuilder { +pub struct NetworkDriverBuilder { /// The chain ID of the network. chain_id: Option, /// The unsafe block signer. @@ -22,10 +29,16 @@ pub struct GossipDriverBuilder { inner: Option, /// The [Keypair] for the node. keypair: Option, + /// The [TcpConfig] for the swarm. + tcp_config: Option, + // /// The [NoiseConfig] for the swarm. + // noise_config: Option, + /// The [YamuxConfig] for the swarm. + yamux_config: Option, } -impl GossipDriverBuilder { - /// Creates a new [GossipDriverBuilder]. +impl NetworkDriverBuilder { + /// Creates a new [NetworkDriverBuilder]. pub fn new() -> Self { Self::default() } @@ -54,6 +67,24 @@ impl GossipDriverBuilder { 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 + } + // TODO: extend builder with [ConfigBuilder] methods. /// Specifies the [ConfigBuilder] for the `gossipsub` configuration. @@ -62,8 +93,8 @@ impl GossipDriverBuilder { self } - /// Builds the [GossipDriver]. - pub fn build(self) -> Result { + /// Builds the [NetworkDriver]. + pub fn build(self) -> Result { // Build the config for gossipsub. let config = self.inner.unwrap_or(config::default_config_builder()).build()?; let unsafe_block_signer = @@ -72,20 +103,35 @@ impl GossipDriverBuilder { // Create the block handler. let (unsafe_block_signer_sender, unsafe_block_signer_recv) = channel(unsafe_block_signer); - let (block_handler, unsafe_block_recv) = - BlockHandler::new(chain_id, unsafe_block_signer_recv); + let (handler, unsafe_block_recv) = BlockHandler::new(chain_id, unsafe_block_signer_recv); // Construct the gossipsub behaviour. - let behaviour = Behaviour::new(config, &[Box::new(block_handler.clone())])?; + let behaviour = Behaviour::new(config, &[Box::new(handler.clone())])?; + + // Build the swarm. + let keypair = self.keypair.unwrap_or(Keypair::generate_secp256k1()); + let swarm = SwarmBuilder::with_existing_identity(keypair) + .with_tokio() + .with_tcp(self.tcp_config.unwrap_or_default(), NoiseConfig::new, || { + self.yamux_config.unwrap_or_default() + })? + .with_behaviour(|_| behaviour)? + .build(); + let addr = self.socket.ok_or_else(|| eyre::eyre!("socket address not set"))?; + let addr = NetworkAddress::try_from(addr)?; + let swarm_addr = Multiaddr::from(addr); + let swarm = SwarmDriver::new(swarm, swarm_addr); + + // Build the discovery service + let discovery = + DiscoveryBuilder::new().with_address(addr).with_chain_id(chain_id).build()?; - Ok(GossipDriver { - behaviour, + Ok(NetworkDriver { unsafe_block_recv, unsafe_block_signer_sender, - chain_id, - handler: block_handler, - addr: self.socket.ok_or_else(|| eyre::eyre!("socket address not set"))?, - keypair: self.keypair.unwrap_or(Keypair::generate_secp256k1()), + handler, + swarm, + discovery, }) } } diff --git a/crates/net/src/discovery.rs b/crates/net/src/discovery.rs index 910ec1e..2457024 100644 --- a/crates/net/src/discovery.rs +++ b/crates/net/src/discovery.rs @@ -49,8 +49,8 @@ impl DiscoveryBuilder { self } - /// Generates an [Enr] and creates a [Discv5] service struct - fn create_disc(&self) -> Result { + /// Builds a [DiscoveryDriver]. + pub fn build(self) -> Result { let addr = self.address.ok_or_else(|| eyre::eyre!("address not set"))?; let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; let opstack = OpStackEnr::new(chain_id, 0); @@ -61,7 +61,25 @@ impl DiscoveryBuilder { let listen_config = ListenConfig::from_ip(addr.ip.into(), addr.port); let config = ConfigBuilder::new(listen_config).build(); - Discv5::new(enr, key, config).map_err(|_| eyre::eyre!("could not create disc service")) + let disc = Discv5::new(enr, key, config) + .map_err(|_| eyre::eyre!("could not create disc service"))?; + + Ok(DiscoveryDriver::new(disc, chain_id)) + } +} + +/// The discovery driver handles running the discovery service. +pub struct DiscoveryDriver { + /// The [Discv5] discovery service. + disc: Discv5, + /// The chain ID of the network. + chain_id: u64, +} + +impl DiscoveryDriver { + /// Instantiates a new [DiscoveryDriver]. + pub fn new(disc: Discv5, chain_id: u64) -> Self { + Self { disc, chain_id } } /// Spawns a new [Discv5] discovery service in a new tokio task. @@ -82,11 +100,12 @@ impl DiscoveryBuilder { /// #[tokio::main] /// async fn main() { /// let network_addr = NetworkAddress { ip: Ipv4Addr::new(127, 0, 0, 1), port: 9000 }; - /// let mut peer_recv = DiscoveryBuilder::new() + /// let mut discovery = DiscoveryBuilder::new() /// .with_address(network_addr) /// .with_chain_id(10) // OP Mainnet chain id - /// .start() - /// .expect("Failed to start discovery service"); + /// .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 { @@ -95,32 +114,27 @@ impl DiscoveryBuilder { /// } /// } /// ``` - pub fn start(self) -> Result> { - let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; - + pub fn start(mut self) -> Result> { // Clone the bootnodes since the spawned thread takes mutable ownership. let bootnodes = BOOTNODES.clone(); - // Construct the discovery service. - let mut disc = self.create_disc()?; - // 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| _ = disc.add_enr(enr)); - disc.start().await.unwrap(); + bootnodes.into_iter().for_each(|enr| _ = self.disc.add_enr(enr)); + self.disc.start().await.unwrap(); trace!("Started peer discovery"); loop { let target = NodeId::random(); - match disc.find_node(target).await { + match self.disc.find_node(target).await { Ok(nodes) => { let peers = nodes .iter() - .filter(|node| OpStackEnr::is_valid_node(node, chain_id)) + .filter(|node| OpStackEnr::is_valid_node(node, self.chain_id)) .flat_map(Peer::try_from); for peer in peers { diff --git a/crates/net/src/driver.rs b/crates/net/src/driver.rs index 5b22932..2256caf 100644 --- a/crates/net/src/driver.rs +++ b/crates/net/src/driver.rs @@ -2,79 +2,62 @@ use alloy::primitives::Address; use eyre::Result; -use futures::stream::StreamExt; -use libp2p::{swarm::SwarmEvent, Multiaddr, SwarmBuilder}; -use libp2p_identity::Keypair; -use std::net::SocketAddr; +use libp2p::swarm::SwarmEvent; use tokio::{ select, sync::watch::{Receiver, Sender}, }; use crate::{ - behaviour::Behaviour, - discovery::DiscoveryBuilder, + discovery::DiscoveryDriver, event::Event, handler::{BlockHandler, Handler}, - types::{ExecutionPayloadEnvelope, NetworkAddress}, + swarm::SwarmDriver, + types::ExecutionPayloadEnvelope, }; -/// Driver contains the logic for the P2P service. -pub struct GossipDriver { - /// The [Behaviour] of the node. - pub behaviour: Behaviour, +/// 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 unsafe_block_recv: Receiver, /// Channel to send unsafe signer updates. pub unsafe_block_signer_sender: Sender
, - /// The socket address that the service is listening on. - pub addr: SocketAddr, /// Block handler. pub handler: BlockHandler, - /// The chain ID of the network. - pub chain_id: u64, - /// A unique keypair to validate the node's identity - pub keypair: Keypair, + /// The swarm instance. + pub swarm: SwarmDriver, + /// The discovery service driver. + pub discovery: DiscoveryDriver, } -impl GossipDriver { +impl NetworkDriver { /// Starts the Discv5 peer discovery & libp2p services /// and continually listens for new peers and messages to handle - pub fn start(self) -> Result<()> { - // TODO: pull this swarm building out into the builder - let mut swarm = SwarmBuilder::with_existing_identity(self.keypair.clone()) - .with_tokio() - .with_tcp( - libp2p::tcp::Config::default(), - libp2p::noise::Config::new, - libp2p::yamux::Config::default, - )? - .with_behaviour(|_| self.behaviour)? - .build(); - let addr = NetworkAddress::try_from(self.addr)?; - let mut peer_recv = - DiscoveryBuilder::new().with_address(addr).with_chain_id(self.chain_id).start()?; - let multiaddr = Multiaddr::from(addr); - swarm.listen_on(multiaddr).map_err(|_| eyre::eyre!("swarm listen failed"))?; - let handler = self.handler.clone(); + pub fn start(mut self) -> Result<()> { + let mut peer_recv = self.discovery.start()?; + self.swarm.listen()?; tokio::spawn(async move { loop { select! { peer = peer_recv.recv() => { if let Some(peer) = peer { - let peer = Multiaddr::from(peer); - _ = swarm.dial(peer); + _ = self.swarm.dial(peer); } }, - event = swarm.select_next_some() => { + event = self.swarm.select_next_some() => { if let SwarmEvent::Behaviour(Event::Gossipsub(libp2p::gossipsub::Event::Message { propagation_source: src, message_id: id, message, })) = event { - if handler.topics().contains(&message.topic) { - let status = handler.handle(message); - _ = swarm + if self.handler.topics().contains(&message.topic) { + let status = self.handler.handle(message); + _ = self.swarm .behaviour_mut() .gossipsub .report_message_validation_result(&id, &src, status); diff --git a/crates/net/src/handler.rs b/crates/net/src/handler.rs index ea2c340..a1ed506 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/handler.rs @@ -5,9 +5,11 @@ use alloy::primitives::Address; use libp2p::gossipsub::{IdentTopic, Message, MessageAcceptance, TopicHash}; use std::time::SystemTime; use tokio::sync::watch::{channel, Receiver, Sender}; -// use ssz_rs::{prelude::*, List, Vector, U256}; -use crate::types::ExecutionPayloadEnvelope; +use crate::{ + ssz::{ExecutionPayloadV1SSZ, ExecutionPayloadV2SSZ, ExecutionPayloadV3SSZ}, + types::ExecutionPayloadEnvelope, +}; /// This trait defines the functionality required to process incoming messages /// and determine their acceptance within the network. Implementors of this trait @@ -44,34 +46,31 @@ impl Handler for BlockHandler { fn handle(&self, msg: Message) -> MessageAcceptance { tracing::debug!("received block"); - if msg.topic == self.blocks_v1_topic.hash() { - // decode_pre_ecotone_block_msg::(msg.data) - unimplemented!() + let decoded = if msg.topic == self.blocks_v1_topic.hash() { + ExecutionPayloadEnvelope::decode_v1(&msg.data) } else if msg.topic == self.blocks_v2_topic.hash() { - // decode_pre_ecotone_block_msg::(msg.data) - unimplemented!() + ExecutionPayloadEnvelope::decode_v2(&msg.data) } else if msg.topic == self.blocks_v3_topic.hash() { - // decode_post_ecotone_block_msg(msg.data) - unimplemented!() + ExecutionPayloadEnvelope::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 - // } - // } + match decoded { + Ok(envelope) => { + if self.block_valid(&envelope) { + _ = self.block_sender.send(envelope); + 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 diff --git a/crates/net/src/lib.rs b/crates/net/src/lib.rs index 44276eb..6718a01 100644 --- a/crates/net/src/lib.rs +++ b/crates/net/src/lib.rs @@ -13,4 +13,6 @@ pub mod driver; pub mod event; pub mod handler; pub mod op_enr; +pub mod ssz; +pub mod swarm; pub mod types; diff --git a/crates/net/src/op_enr.rs b/crates/net/src/op_enr.rs index ad306ea..977a630 100644 --- a/crates/net/src/op_enr.rs +++ b/crates/net/src/op_enr.rs @@ -1,9 +1,12 @@ -//! Contains the OP Stack Enr Type. +//! Contains the Optimism consensus-layer ENR Type. use discv5::enr::{CombinedKey, Enr}; use eyre::Result; 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)] pub struct OpStackEnr { @@ -21,7 +24,7 @@ impl OpStackEnr { /// 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("opstack") + node.get_raw_rlp(OP_CL_KEY) .map(|opstack| { OpStackEnr::try_from(opstack) .map(|opstack| opstack.chain_id == chain_id && opstack.version == 0) diff --git a/crates/net/src/ssz.rs b/crates/net/src/ssz.rs new file mode 100644 index 0000000..9e9a860 --- /dev/null +++ b/crates/net/src/ssz.rs @@ -0,0 +1,245 @@ +//! SSZ Types + +use kona_primitives::L2ExecutionPayload; +use ssz_rs::{prelude::*, List, Vector, U256}; + +/// A type alias for a vector of 32 bytes, representing a Bytes32 hash +type Bytes32 = Vector; +/// A type alias for a vector of 20 bytes, representing an address +type VecAddress = Vector; +/// A type alias for a byte list, representing a transaction +type Transaction = List; + +/// The pre Canyon/Shanghai [ExecutionPayload] - the withdrawals field should not exist +#[derive(SimpleSerialize, Default)] +pub struct ExecutionPayloadV1SSZ { + /// Block hash of the parent block + pub parent_hash: Bytes32, + /// Fee recipient of the block. Set to the sequencer fee vault + pub fee_recipient: VecAddress, + /// State root of the block + pub state_root: Bytes32, + /// Receipts root of the block + pub receipts_root: Bytes32, + /// Logs bloom of the block + pub logs_bloom: Vector, + /// The block mix_digest + pub prev_randao: Bytes32, + /// The block number + pub block_number: u64, + /// The block gas limit + pub gas_limit: u64, + /// Total gas used in the block + pub gas_used: u64, + /// Timestamp of the block + pub timestamp: u64, + /// Any extra data included in the block + pub extra_data: List, + /// Base fee per gas of the block + pub base_fee_per_gas: U256, + /// Hash of the block + pub block_hash: Bytes32, + /// Transactions in the block + pub transactions: List, +} + +impl From for L2ExecutionPayload { + fn from(value: ExecutionPayloadV1SSZ) -> Self { + Self { + parent_hash: convert_hash(value.parent_hash), + fee_recipient: convert_address(value.fee_recipient), + state_root: convert_hash(value.state_root), + receipts_root: convert_hash(value.receipts_root), + logs_bloom: convert_bloom(value.logs_bloom), + prev_randao: convert_hash(value.prev_randao), + block_number: value.block_number, + gas_limit: value.gas_limit.into(), + gas_used: value.gas_used.into(), + timestamp: value.timestamp, + extra_data: convert_byte_list(value.extra_data), + base_fee_per_gas: convert_uint(value.base_fee_per_gas), + block_hash: convert_hash(value.block_hash), + transactions: convert_tx_list(value.transactions), + deserialized_transactions: Vec::default(), + withdrawals: None, + blob_gas_used: None, + excess_blob_gas: None, + } + } +} + +/// The Canyon/Shanghai [ExecutionPayload] - the withdrawals field should be an empty [List] +#[derive(SimpleSerialize, Default)] +pub struct ExecutionPayloadV2SSZ { + /// Block hash of the parent block + pub parent_hash: Bytes32, + /// Fee recipient of the block. Set to the sequencer fee vault + pub fee_recipient: VecAddress, + /// State root of the block + pub state_root: Bytes32, + /// Receipts root of the block + pub receipts_root: Bytes32, + /// Logs bloom of the block + pub logs_bloom: Vector, + /// The block mix_digest + pub prev_randao: Bytes32, + /// The block number + pub block_number: u64, + /// The block gas limit + pub gas_limit: u64, + /// Total gas used in the block + pub gas_used: u64, + /// Timestamp of the block + pub timestamp: u64, + /// Any extra data included in the block + pub extra_data: List, + /// Base fee per gas of the block + pub base_fee_per_gas: U256, + /// Hash of the block + pub block_hash: Bytes32, + /// Transactions in the block + pub transactions: List, + /// An empty list. This is unused and only exists for L1 compatibility. + pub withdrawals: List, +} + +/// This represents an L1 validator Withdrawal, and is unused in OP stack rollups. +/// Exists only for L1 compatibility +#[derive(SimpleSerialize, Default)] +pub struct Withdrawal { + /// Index of the withdrawal + index: u64, + /// Index of the validator + validator_index: u64, + /// Account address that has withdrawn + address: VecAddress, + /// The amount withdrawn + amount: u64, +} + +impl From for L2ExecutionPayload { + /// Converts an ExecutionPayloadV2SSZ received via p2p gossip into an [ExecutionPayload] used by + /// the engine. + fn from(value: ExecutionPayloadV2SSZ) -> Self { + Self { + parent_hash: convert_hash(value.parent_hash), + fee_recipient: convert_address(value.fee_recipient), + state_root: convert_hash(value.state_root), + receipts_root: convert_hash(value.receipts_root), + logs_bloom: convert_bloom(value.logs_bloom), + prev_randao: convert_hash(value.prev_randao), + block_number: value.block_number, + gas_limit: value.gas_limit.into(), + gas_used: value.gas_used.into(), + timestamp: value.timestamp, + extra_data: convert_byte_list(value.extra_data), + base_fee_per_gas: convert_uint(value.base_fee_per_gas), + block_hash: convert_hash(value.block_hash), + transactions: convert_tx_list(value.transactions), + deserialized_transactions: Vec::default(), + withdrawals: Some(Vec::new()), + blob_gas_used: None, + excess_blob_gas: None, + } + } +} + +/// The Ecotone [ExecutionPayload] - Adds Eip 4844 fields to the payload +/// - `blob_gas_used` +/// - `excess_blob_gas` +#[derive(SimpleSerialize, Default)] +pub struct ExecutionPayloadV3SSZ { + /// Block hash of the parent block + pub parent_hash: Bytes32, + /// Fee recipient of the block. Set to the sequencer fee vault + pub fee_recipient: VecAddress, + /// State root of the block + pub state_root: Bytes32, + /// Receipts root of the block + pub receipts_root: Bytes32, + /// Logs bloom of the block + pub logs_bloom: Vector, + /// The block mix_digest + pub prev_randao: Bytes32, + /// The block number + pub block_number: u64, + /// The block gas limit + pub gas_limit: u64, + /// Total gas used in the block + pub gas_used: u64, + /// Timestamp of the block + pub timestamp: u64, + /// Any extra data included in the block + pub extra_data: List, + /// Base fee per gas of the block + pub base_fee_per_gas: U256, + /// Hash of the block + pub block_hash: Bytes32, + /// Transactions in the block + pub transactions: List, + /// An empty list. This is unused and only exists for L1 compatibility. + pub withdrawals: List, + /// The total gas used by the blob in the block + pub blob_gas_used: u64, + /// The excess gas used by the blob in the block + pub excess_blob_gas: u64, +} + +impl From for L2ExecutionPayload { + fn from(value: ExecutionPayloadV3SSZ) -> Self { + Self { + parent_hash: convert_hash(value.parent_hash), + fee_recipient: convert_address(value.fee_recipient), + state_root: convert_hash(value.state_root), + receipts_root: convert_hash(value.receipts_root), + logs_bloom: convert_bloom(value.logs_bloom), + prev_randao: convert_hash(value.prev_randao), + block_number: value.block_number, + gas_limit: value.gas_limit.into(), + gas_used: value.gas_used.into(), + timestamp: value.timestamp, + extra_data: convert_byte_list(value.extra_data), + base_fee_per_gas: convert_uint(value.base_fee_per_gas), + block_hash: convert_hash(value.block_hash), + transactions: convert_tx_list(value.transactions), + deserialized_transactions: Vec::default(), + withdrawals: Some(Vec::new()), + blob_gas_used: Some(value.blob_gas_used.into()), + excess_blob_gas: Some(value.excess_blob_gas.into()), + } + } +} + +/// Converts an [ssz_rs::Vector] of bytes into [alloy::primitives::Bloom] +fn convert_bloom(vector: Vector) -> alloy::primitives::Bloom { + let mut bloom = [0u8; 256]; + bloom.copy_from_slice(vector.as_ref()); + alloy::primitives::Bloom::from(bloom) +} + +/// Converts [Bytes32] into [alloy::primitives::B256] +fn convert_hash(bytes: Bytes32) -> alloy::primitives::B256 { + alloy::primitives::B256::from_slice(bytes.as_slice()) +} + +/// Converts [VecAddress] into [alloy::primitives::Address] +fn convert_address(address: VecAddress) -> alloy::primitives::Address { + alloy::primitives::Address::from_slice(address.as_slice()) +} + +/// Converts an [ssz_rs::List] of bytes into [alloy::primitives::Bytes] +fn convert_byte_list(list: List) -> alloy::primitives::Bytes { + alloy::primitives::Bytes::from(list.to_vec()) +} + +/// Converts a [U256] into [u128] +fn convert_uint(value: U256) -> Option { + let bytes = value.to_bytes_le(); + let bytes: [u8; 16] = bytes.try_into().ok()?; + Some(u128::from_le_bytes(bytes)) +} + +/// Converts [ssz_rs::List] of [Transaction] into a vector of [alloy::primitives::Bytes] +fn convert_tx_list(value: List) -> Vec { + value.iter().map(|tx| alloy::primitives::Bytes::from(tx.to_vec())).collect() +} diff --git a/crates/net/src/swarm.rs b/crates/net/src/swarm.rs new file mode 100644 index 0000000..2a0fe05 --- /dev/null +++ b/crates/net/src/swarm.rs @@ -0,0 +1,43 @@ +//! Helpers for working with a [libp2p::Swarm]. + +use eyre::Result; +use futures::stream::StreamExt; +use libp2p::{Multiaddr, Swarm}; + +/// A [libp2p::Swarm] instance with an associated address to listen on. +pub struct SwarmDriver { + /// The [libp2p::Swarm] instance. + pub swarm: Swarm, + /// The address to listen on. + pub addr: Multiaddr, +} + +impl SwarmDriver { + /// Creates a new [SwarmWithAddr] instance. + pub fn new(swarm: Swarm, addr: Multiaddr) -> Self { + Self { swarm, addr } + } + + /// Listens on the address. + pub fn listen(&mut self) -> Result<()> { + self.swarm.listen_on(self.addr.clone()).map_err(|_| eyre::eyre!("swarm listen failed"))?; + Ok(()) + } + + /// Returns a mutable reference to the Swarm's behaviour. + pub fn behaviour_mut(&mut self) -> &mut crate::behaviour::Behaviour { + self.swarm.behaviour_mut() + } + + /// Attempts to select the next event from the Swarm. + pub async fn select_next_some(&mut self) -> libp2p::swarm::SwarmEvent { + self.swarm.select_next_some().await + } + + /// 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(|_| eyre::eyre!("dial failed"))?; + Ok(()) + } +} diff --git a/crates/net/src/types.rs b/crates/net/src/types.rs index 44e01e2..9f46ec9 100644 --- a/crates/net/src/types.rs +++ b/crates/net/src/types.rs @@ -5,11 +5,14 @@ use discv5::enr::{CombinedKey, Enr}; use eyre::Result; use kona_primitives::L2ExecutionPayload; use libp2p::{multiaddr::Protocol, Multiaddr}; +use ssz_rs::prelude::*; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, str::FromStr, }; +use crate::ssz::{ExecutionPayloadV1SSZ, ExecutionPayloadV2SSZ, ExecutionPayloadV3SSZ}; + /// An envelope around the execution payload for L2. #[derive(Debug, Clone)] pub struct ExecutionPayloadEnvelope { @@ -23,6 +26,62 @@ pub struct ExecutionPayloadEnvelope { pub parent_beacon_block_root: Option, } +impl ExecutionPayloadEnvelope { + /// Decode V1 + pub fn decode_v1(data: &[u8]) -> Result { + let mut decoder = snap::raw::Decoder::new(); + let decompressed = decoder.decompress_vec(data)?; + let sig_data = &decompressed[..65]; + let block_data = &decompressed[65..]; + + let signature = Signature::try_from(sig_data)?; + + let payload = ExecutionPayloadV1SSZ::deserialize(block_data)?; + let payload = L2ExecutionPayload::from(payload); + + let hash = PayloadHash::from(block_data); + + Ok(ExecutionPayloadEnvelope { parent_beacon_block_root: None, signature, payload, hash }) + } + + /// Decode V2 + pub fn decode_v2(data: &[u8]) -> Result { + let mut decoder = snap::raw::Decoder::new(); + let decompressed = decoder.decompress_vec(data)?; + let sig_data = &decompressed[..65]; + let block_data = &decompressed[65..]; + + let signature = Signature::try_from(sig_data)?; + + let payload = ExecutionPayloadV2SSZ::deserialize(block_data)?; + let payload = L2ExecutionPayload::from(payload); + + let hash = PayloadHash::from(block_data); + + Ok(ExecutionPayloadEnvelope { parent_beacon_block_root: None, signature, payload, hash }) + } + + /// Decode V3 + pub fn decode_v3(data: &[u8]) -> Result { + let mut decoder = snap::raw::Decoder::new(); + let decompressed = decoder.decompress_vec(data)?; + let sig_data = &decompressed[..65]; + let parent_beacon_block_root = &decompressed[65..97]; + let block_data = &decompressed[97..]; + + let signature = Signature::try_from(sig_data)?; + + let parent_beacon_block_root = Some(B256::from_slice(parent_beacon_block_root)); + + let payload = ExecutionPayloadV3SSZ::deserialize(block_data)?; + let payload = L2ExecutionPayload::from(payload); + + let hash = PayloadHash::from(block_data); + + Ok(ExecutionPayloadEnvelope { parent_beacon_block_root, signature, payload, hash }) + } +} + impl Default for ExecutionPayloadEnvelope { fn default() -> Self { Self { From c4b0d999869f3ff414b40e0f90b2ba56f7f43cc2 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 13:25:23 -0400 Subject: [PATCH 10/16] fix(net): workspace kona-primitives dep --- crates/net/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml index 1867fb3..7958beb 100644 --- a/crates/net/Cargo.toml +++ b/crates/net/Cargo.toml @@ -16,7 +16,7 @@ alloy.workspace = true alloy-rlp.workspace = true # Kona -kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } +kona-primitives.workspace = true # Networking ssz_rs.workspace = true From bbdb07bb32737108a1b4b2f8f6079e05e829c1a3 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 13:26:42 -0400 Subject: [PATCH 11/16] fix(net): remove unused allow --- crates/net/src/handler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/net/src/handler.rs b/crates/net/src/handler.rs index a1ed506..b4d058d 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/handler.rs @@ -1,4 +1,3 @@ -#![allow(unused)] //! Block Handler use alloy::primitives::Address; From da648860e4ebf7274c4461d17e76bb5fbeaf01c0 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 13:27:34 -0400 Subject: [PATCH 12/16] fix(net): remove unused imports --- crates/net/src/handler.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/net/src/handler.rs b/crates/net/src/handler.rs index b4d058d..9e20d1e 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/handler.rs @@ -5,10 +5,7 @@ use libp2p::gossipsub::{IdentTopic, Message, MessageAcceptance, TopicHash}; use std::time::SystemTime; use tokio::sync::watch::{channel, Receiver, Sender}; -use crate::{ - ssz::{ExecutionPayloadV1SSZ, ExecutionPayloadV2SSZ, ExecutionPayloadV3SSZ}, - types::ExecutionPayloadEnvelope, -}; +use crate::types::ExecutionPayloadEnvelope; /// This trait defines the functionality required to process incoming messages /// and determine their acceptance within the network. Implementors of this trait From 20d8f380f9f88aa248f8f3c33f3a6189f6c911f6 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 14:50:24 -0400 Subject: [PATCH 13/16] fix(net): rework the net crate --- crates/net/src/builder.rs | 8 +- crates/net/src/{ => discovery}/bootnodes.rs | 0 crates/net/src/discovery/builder.rs | 57 +++++ .../src/{discovery.rs => discovery/driver.rs} | 58 +---- crates/net/src/discovery/mod.rs | 5 + crates/net/src/driver.rs | 14 +- crates/net/src/{ => gossip}/behaviour.rs | 12 +- crates/net/src/{ => gossip}/config.rs | 0 crates/net/src/{swarm.rs => gossip/driver.rs} | 15 +- crates/net/src/{ => gossip}/event.rs | 0 crates/net/src/{ => gossip}/handler.rs | 2 +- crates/net/src/gossip/mod.rs | 7 + crates/net/src/lib.rs | 14 +- crates/net/src/types.rs | 210 ------------------ crates/net/src/types/address.rs | 83 +++++++ crates/net/src/{op_enr.rs => types/enr.rs} | 0 crates/net/src/types/envelope.rs | 93 ++++++++ crates/net/src/types/mod.rs | 6 + crates/net/src/{ssz.rs => types/payload.rs} | 41 +++- 19 files changed, 325 insertions(+), 300 deletions(-) rename crates/net/src/{ => discovery}/bootnodes.rs (100%) create mode 100644 crates/net/src/discovery/builder.rs rename crates/net/src/{discovery.rs => discovery/driver.rs} (63%) create mode 100644 crates/net/src/discovery/mod.rs rename crates/net/src/{ => gossip}/behaviour.rs (87%) rename crates/net/src/{ => gossip}/config.rs (100%) rename crates/net/src/{swarm.rs => gossip/driver.rs} (76%) rename crates/net/src/{ => gossip}/event.rs (100%) rename crates/net/src/{ => gossip}/handler.rs (98%) create mode 100644 crates/net/src/gossip/mod.rs delete mode 100644 crates/net/src/types.rs create mode 100644 crates/net/src/types/address.rs rename crates/net/src/{op_enr.rs => types/enr.rs} (100%) create mode 100644 crates/net/src/types/envelope.rs create mode 100644 crates/net/src/types/mod.rs rename crates/net/src/{ssz.rs => types/payload.rs} (88%) diff --git a/crates/net/src/builder.rs b/crates/net/src/builder.rs index c126ad8..9a745c4 100644 --- a/crates/net/src/builder.rs +++ b/crates/net/src/builder.rs @@ -12,8 +12,10 @@ use libp2p::{ use libp2p_identity::Keypair; use crate::{ - behaviour::Behaviour, config, discovery::DiscoveryBuilder, driver::NetworkDriver, - handler::BlockHandler, swarm::SwarmDriver, types::NetworkAddress, + discovery::builder::DiscoveryBuilder, + driver::NetworkDriver, + gossip::{behaviour::Behaviour, config, driver::GossipDriver, handler::BlockHandler}, + types::address::NetworkAddress, }; /// Constructs a [NetworkDriver] for Optimism's consensus-layer. @@ -120,7 +122,7 @@ impl NetworkDriverBuilder { let addr = self.socket.ok_or_else(|| eyre::eyre!("socket address not set"))?; let addr = NetworkAddress::try_from(addr)?; let swarm_addr = Multiaddr::from(addr); - let swarm = SwarmDriver::new(swarm, swarm_addr); + let swarm = GossipDriver::new(swarm, swarm_addr); // Build the discovery service let discovery = diff --git a/crates/net/src/bootnodes.rs b/crates/net/src/discovery/bootnodes.rs similarity index 100% rename from crates/net/src/bootnodes.rs rename to crates/net/src/discovery/bootnodes.rs diff --git a/crates/net/src/discovery/builder.rs b/crates/net/src/discovery/builder.rs new file mode 100644 index 0000000..fe1cf02 --- /dev/null +++ b/crates/net/src/discovery/builder.rs @@ -0,0 +1,57 @@ +//! Contains a builder for the discovery service. + +use crate::{ + discovery::driver::DiscoveryDriver, + types::{address::NetworkAddress, enr::OpStackEnr}, +}; +use discv5::{ + enr::{CombinedKey, Enr}, + ConfigBuilder, Discv5, ListenConfig, +}; +use eyre::Result; + +/// 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, +} + +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: NetworkAddress) -> 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 + } + + /// Builds a [DiscoveryDriver]. + pub fn build(self) -> Result { + let addr = self.address.ok_or_else(|| eyre::eyre!("address not set"))?; + let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; + let opstack = OpStackEnr::new(chain_id, 0); + let opstack_data: Vec = opstack.into(); + + let key = CombinedKey::generate_secp256k1(); + let enr = Enr::builder().add_value_rlp("opstack", opstack_data.into()).build(&key)?; + let listen_config = ListenConfig::from_ip(addr.ip.into(), addr.port); + let config = ConfigBuilder::new(listen_config).build(); + + 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.rs b/crates/net/src/discovery/driver.rs similarity index 63% rename from crates/net/src/discovery.rs rename to crates/net/src/discovery/driver.rs index 2457024..0a2d3a9 100644 --- a/crates/net/src/discovery.rs +++ b/crates/net/src/discovery/driver.rs @@ -8,66 +8,16 @@ use tokio::{ }; use tracing::{trace, warn}; -use discv5::{ - enr::{CombinedKey, Enr, NodeId}, - ConfigBuilder, Discv5, ListenConfig, -}; +use discv5::{enr::NodeId, Discv5}; use crate::{ - bootnodes::BOOTNODES, - op_enr::OpStackEnr, - types::{NetworkAddress, Peer}, + discovery::bootnodes::BOOTNODES, + types::{address::Peer, enr::OpStackEnr}, }; /// The number of peers to buffer in the channel. const DISCOVERY_PEER_CHANNEL_SIZE: usize = 256; -/// 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, -} - -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: NetworkAddress) -> 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 - } - - /// Builds a [DiscoveryDriver]. - pub fn build(self) -> Result { - let addr = self.address.ok_or_else(|| eyre::eyre!("address not set"))?; - let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; - let opstack = OpStackEnr::new(chain_id, 0); - let opstack_data: Vec = opstack.into(); - - let key = CombinedKey::generate_secp256k1(); - let enr = Enr::builder().add_value_rlp("opstack", opstack_data.into()).build(&key)?; - let listen_config = ListenConfig::from_ip(addr.ip.into(), addr.port); - let config = ConfigBuilder::new(listen_config).build(); - - let disc = Discv5::new(enr, key, config) - .map_err(|_| eyre::eyre!("could not create disc service"))?; - - Ok(DiscoveryDriver::new(disc, chain_id)) - } -} - /// The discovery driver handles running the discovery service. pub struct DiscoveryDriver { /// The [Discv5] discovery service. @@ -94,7 +44,7 @@ impl DiscoveryDriver { /// ## Example /// /// ```no_run - /// use op_net::{discovery::DiscoveryBuilder, types::NetworkAddress}; + /// use op_net::{discovery::builder::DiscoveryBuilder, types::address::NetworkAddress}; /// use std::net::Ipv4Addr; /// /// #[tokio::main] 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 index 2256caf..c91cbfe 100644 --- a/crates/net/src/driver.rs +++ b/crates/net/src/driver.rs @@ -9,11 +9,13 @@ use tokio::{ }; use crate::{ - discovery::DiscoveryDriver, - event::Event, - handler::{BlockHandler, Handler}, - swarm::SwarmDriver, - types::ExecutionPayloadEnvelope, + discovery::driver::DiscoveryDriver, + gossip::{ + driver::GossipDriver, + event::Event, + handler::{BlockHandler, Handler}, + }, + types::envelope::ExecutionPayloadEnvelope, }; /// NetworkDriver @@ -30,7 +32,7 @@ pub struct NetworkDriver { /// Block handler. pub handler: BlockHandler, /// The swarm instance. - pub swarm: SwarmDriver, + pub swarm: GossipDriver, /// The discovery service driver. pub discovery: DiscoveryDriver, } diff --git a/crates/net/src/behaviour.rs b/crates/net/src/gossip/behaviour.rs similarity index 87% rename from crates/net/src/behaviour.rs rename to crates/net/src/gossip/behaviour.rs index 861e543..fa2cdf2 100644 --- a/crates/net/src/behaviour.rs +++ b/crates/net/src/gossip/behaviour.rs @@ -6,7 +6,7 @@ use libp2p::{ swarm::NetworkBehaviour, }; -use crate::{event::Event, handler::Handler}; +use super::{event::Event, handler::Handler}; /// Specifies the [NetworkBehaviour] of the node #[derive(NetworkBehaviour)] @@ -48,7 +48,7 @@ impl Behaviour { #[cfg(test)] mod tests { use super::*; - use crate::handler::BlockHandler; + use crate::gossip::{config, handler::BlockHandler}; use alloy::primitives::Address; use libp2p::gossipsub::{IdentTopic, TopicHash}; @@ -62,18 +62,14 @@ mod tests { #[test] fn test_behaviour_no_handlers() { - let cfg = crate::config::default_config_builder() - .build() - .expect("Failed to build default config"); + 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 = crate::config::default_config_builder() - .build() - .expect("Failed to build default config"); + 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)]; diff --git a/crates/net/src/config.rs b/crates/net/src/gossip/config.rs similarity index 100% rename from crates/net/src/config.rs rename to crates/net/src/gossip/config.rs diff --git a/crates/net/src/swarm.rs b/crates/net/src/gossip/driver.rs similarity index 76% rename from crates/net/src/swarm.rs rename to crates/net/src/gossip/driver.rs index 2a0fe05..f5c5050 100644 --- a/crates/net/src/swarm.rs +++ b/crates/net/src/gossip/driver.rs @@ -1,20 +1,21 @@ -//! Helpers for working with a [libp2p::Swarm]. +//! Consensus-layer gossipsub driver for Optimism. +use crate::gossip::{behaviour::Behaviour, event::Event}; use eyre::Result; use futures::stream::StreamExt; use libp2p::{Multiaddr, Swarm}; /// A [libp2p::Swarm] instance with an associated address to listen on. -pub struct SwarmDriver { +pub struct GossipDriver { /// The [libp2p::Swarm] instance. - pub swarm: Swarm, + pub swarm: Swarm, /// The address to listen on. pub addr: Multiaddr, } -impl SwarmDriver { +impl GossipDriver { /// Creates a new [SwarmWithAddr] instance. - pub fn new(swarm: Swarm, addr: Multiaddr) -> Self { + pub fn new(swarm: Swarm, addr: Multiaddr) -> Self { Self { swarm, addr } } @@ -25,12 +26,12 @@ impl SwarmDriver { } /// Returns a mutable reference to the Swarm's behaviour. - pub fn behaviour_mut(&mut self) -> &mut crate::behaviour::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) -> libp2p::swarm::SwarmEvent { + pub async fn select_next_some(&mut self) -> libp2p::swarm::SwarmEvent { self.swarm.select_next_some().await } diff --git a/crates/net/src/event.rs b/crates/net/src/gossip/event.rs similarity index 100% rename from crates/net/src/event.rs rename to crates/net/src/gossip/event.rs diff --git a/crates/net/src/handler.rs b/crates/net/src/gossip/handler.rs similarity index 98% rename from crates/net/src/handler.rs rename to crates/net/src/gossip/handler.rs index 9e20d1e..7ec438e 100644 --- a/crates/net/src/handler.rs +++ b/crates/net/src/gossip/handler.rs @@ -5,7 +5,7 @@ use libp2p::gossipsub::{IdentTopic, Message, MessageAcceptance, TopicHash}; use std::time::SystemTime; use tokio::sync::watch::{channel, Receiver, Sender}; -use crate::types::ExecutionPayloadEnvelope; +use crate::types::envelope::ExecutionPayloadEnvelope; /// This trait defines the functionality required to process incoming messages /// and determine their acceptance within the network. Implementors of this trait 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 index 6718a01..2e97e2d 100644 --- a/crates/net/src/lib.rs +++ b/crates/net/src/lib.rs @@ -4,15 +4,9 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -pub mod behaviour; -pub mod bootnodes; -pub mod builder; -pub mod config; pub mod discovery; -pub mod driver; -pub mod event; -pub mod handler; -pub mod op_enr; -pub mod ssz; -pub mod swarm; +pub mod gossip; pub mod types; + +pub mod builder; +pub mod driver; diff --git a/crates/net/src/types.rs b/crates/net/src/types.rs deleted file mode 100644 index 9f46ec9..0000000 --- a/crates/net/src/types.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! Types for the P2P network. - -use alloy::primitives::{keccak256, Signature, B256}; -use discv5::enr::{CombinedKey, Enr}; -use eyre::Result; -use kona_primitives::L2ExecutionPayload; -use libp2p::{multiaddr::Protocol, Multiaddr}; -use ssz_rs::prelude::*; -use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr}, - str::FromStr, -}; - -use crate::ssz::{ExecutionPayloadV1SSZ, ExecutionPayloadV2SSZ, ExecutionPayloadV3SSZ}; - -/// An envelope around the execution payload for L2. -#[derive(Debug, Clone)] -pub struct ExecutionPayloadEnvelope { - /// The execution payload. - pub payload: L2ExecutionPayload, - /// A signature for the payload. - pub signature: Signature, - /// The hash of the payload. - pub hash: PayloadHash, - /// The parent beacon block root. - pub parent_beacon_block_root: Option, -} - -impl ExecutionPayloadEnvelope { - /// Decode V1 - pub fn decode_v1(data: &[u8]) -> Result { - let mut decoder = snap::raw::Decoder::new(); - let decompressed = decoder.decompress_vec(data)?; - let sig_data = &decompressed[..65]; - let block_data = &decompressed[65..]; - - let signature = Signature::try_from(sig_data)?; - - let payload = ExecutionPayloadV1SSZ::deserialize(block_data)?; - let payload = L2ExecutionPayload::from(payload); - - let hash = PayloadHash::from(block_data); - - Ok(ExecutionPayloadEnvelope { parent_beacon_block_root: None, signature, payload, hash }) - } - - /// Decode V2 - pub fn decode_v2(data: &[u8]) -> Result { - let mut decoder = snap::raw::Decoder::new(); - let decompressed = decoder.decompress_vec(data)?; - let sig_data = &decompressed[..65]; - let block_data = &decompressed[65..]; - - let signature = Signature::try_from(sig_data)?; - - let payload = ExecutionPayloadV2SSZ::deserialize(block_data)?; - let payload = L2ExecutionPayload::from(payload); - - let hash = PayloadHash::from(block_data); - - Ok(ExecutionPayloadEnvelope { parent_beacon_block_root: None, signature, payload, hash }) - } - - /// Decode V3 - pub fn decode_v3(data: &[u8]) -> Result { - let mut decoder = snap::raw::Decoder::new(); - let decompressed = decoder.decompress_vec(data)?; - let sig_data = &decompressed[..65]; - let parent_beacon_block_root = &decompressed[65..97]; - let block_data = &decompressed[97..]; - - let signature = Signature::try_from(sig_data)?; - - let parent_beacon_block_root = Some(B256::from_slice(parent_beacon_block_root)); - - let payload = ExecutionPayloadV3SSZ::deserialize(block_data)?; - let payload = L2ExecutionPayload::from(payload); - - let hash = PayloadHash::from(block_data); - - Ok(ExecutionPayloadEnvelope { parent_beacon_block_root, signature, payload, hash }) - } -} - -impl Default for ExecutionPayloadEnvelope { - fn default() -> Self { - Self { - payload: L2ExecutionPayload::default(), - // Generic signature taken from `alloy_primitives` tests. - // - // https://github.com/alloy-rs/core/blob/main/crates/primitives/src/signature/sig.rs#L614 - signature: Signature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap(), - hash: PayloadHash::default(), - parent_beacon_block_root: None, - } - } -} - -/// Represents the Keccak256 hash of the block -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] -pub struct PayloadHash(B256); - -impl From<&[u8]> for PayloadHash { - /// Returns the Keccak256 hash of a sequence of bytes - fn from(value: &[u8]) -> Self { - Self(keccak256(value)) - } -} - -impl PayloadHash { - /// The expected message that should be signed by the unsafe block signer. - pub fn signature_message(&self, chain_id: u64) -> B256 { - let domain = B256::ZERO.as_slice(); - let chain_id = B256::left_padding_from(&chain_id.to_be_bytes()[..]); - let payload_hash = self.0.as_slice(); - keccak256([domain, chain_id.as_slice(), payload_hash].concat()) - } -} - -/// An [Ipv4Addr] and port. -#[derive(Debug, Clone, Copy)] -pub struct NetworkAddress { - /// An [Ipv4Addr] - pub ip: Ipv4Addr, - /// A port - pub port: u16, -} - -/// A wrapper around a peer's Network Address. -#[derive(Debug)] -pub struct Peer { - /// The peer's [Ipv4Addr] and port - pub addr: NetworkAddress, -} - -impl TryFrom<&Enr> for NetworkAddress { - type Error = eyre::Report; - - /// Convert an [Enr] to a Network Address. - 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"))?; - - Ok(Self { ip, port }) - } -} - -impl From for Multiaddr { - /// Converts a Network Address to a [Multiaddr] - fn from(value: NetworkAddress) -> Self { - let mut multiaddr = Multiaddr::empty(); - multiaddr.push(Protocol::Ip4(value.ip)); - multiaddr.push(Protocol::Tcp(value.port)); - - multiaddr - } -} - -impl From for SocketAddr { - /// Converts a Network Address to a [SocketAddr]. - fn from(value: NetworkAddress) -> Self { - SocketAddr::new(IpAddr::V4(value.ip), value.port) - } -} - -impl TryFrom for NetworkAddress { - type Error = eyre::Report; - - /// Converts a [SocketAddr] to a Network Address. - fn try_from(value: SocketAddr) -> Result { - let ip = match value.ip() { - IpAddr::V4(ip) => ip, - IpAddr::V6(_) => eyre::bail!("ipv6 not supported"), - }; - - Ok(Self { ip, port: value.port() }) - } -} - -impl TryFrom<&Enr> for Peer { - type Error = eyre::Report; - - /// Converts an [Enr] to a Peer - fn try_from(value: &Enr) -> Result { - let addr = NetworkAddress::try_from(value)?; - Ok(Peer { addr }) - } -} - -impl From for Multiaddr { - /// Converts a Peer to a [Multiaddr] - fn from(value: Peer) -> Self { - value.addr.into() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy::primitives::b256; - - #[test] - fn test_signature_message() { - let inner = b256!("9999999999999999999999999999999999999999999999999999999999999999"); - let hash = PayloadHash::from(inner.as_slice()); - let chain_id = 10; - let expected = b256!("44a0e2b1aba1aae1771eddae1dcd2ad18a8cdac8891517153f03253e49d3f206"); - assert_eq!(hash.signature_message(chain_id), expected); - } -} diff --git a/crates/net/src/types/address.rs b/crates/net/src/types/address.rs new file mode 100644 index 0000000..5aec879 --- /dev/null +++ b/crates/net/src/types/address.rs @@ -0,0 +1,83 @@ +//! Types for the P2P network. + +use discv5::enr::{CombinedKey, Enr}; +use eyre::Result; +use libp2p::{multiaddr::Protocol, Multiaddr}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + +/// An [Ipv4Addr] and port. +#[derive(Debug, Clone, Copy)] +pub struct NetworkAddress { + /// An [Ipv4Addr] + pub ip: Ipv4Addr, + /// A port + pub port: u16, +} + +/// A wrapper around a peer's Network Address. +#[derive(Debug)] +pub struct Peer { + /// The peer's [Ipv4Addr] and port + pub addr: NetworkAddress, +} + +impl TryFrom<&Enr> for NetworkAddress { + type Error = eyre::Report; + + /// Convert an [Enr] to a Network Address. + 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"))?; + + Ok(Self { ip, port }) + } +} + +impl From for Multiaddr { + /// Converts a Network Address to a [Multiaddr] + fn from(value: NetworkAddress) -> Self { + let mut multiaddr = Multiaddr::empty(); + multiaddr.push(Protocol::Ip4(value.ip)); + multiaddr.push(Protocol::Tcp(value.port)); + + multiaddr + } +} + +impl From for SocketAddr { + /// Converts a Network Address to a [SocketAddr]. + fn from(value: NetworkAddress) -> Self { + SocketAddr::new(IpAddr::V4(value.ip), value.port) + } +} + +impl TryFrom for NetworkAddress { + type Error = eyre::Report; + + /// Converts a [SocketAddr] to a Network Address. + fn try_from(value: SocketAddr) -> Result { + let ip = match value.ip() { + IpAddr::V4(ip) => ip, + IpAddr::V6(_) => eyre::bail!("ipv6 not supported"), + }; + + Ok(Self { ip, port: value.port() }) + } +} + +impl TryFrom<&Enr> for Peer { + type Error = eyre::Report; + + /// Converts an [Enr] to a Peer + fn try_from(value: &Enr) -> Result { + let addr = NetworkAddress::try_from(value)?; + Ok(Peer { addr }) + } +} + +impl From for Multiaddr { + /// Converts a Peer to a [Multiaddr] + fn from(value: Peer) -> Self { + value.addr.into() + } +} diff --git a/crates/net/src/op_enr.rs b/crates/net/src/types/enr.rs similarity index 100% rename from crates/net/src/op_enr.rs rename to crates/net/src/types/enr.rs diff --git a/crates/net/src/types/envelope.rs b/crates/net/src/types/envelope.rs new file mode 100644 index 0000000..4fa3211 --- /dev/null +++ b/crates/net/src/types/envelope.rs @@ -0,0 +1,93 @@ +//! Execution Payload Envelope Type + +use super::payload::{ + ExecutionPayloadV1SSZ, ExecutionPayloadV2SSZ, ExecutionPayloadV3SSZ, PayloadHash, +}; +use alloy::primitives::{Signature, B256}; +use eyre::Result; +use kona_primitives::L2ExecutionPayload; +use ssz_rs::prelude::*; +use std::str::FromStr; + +/// An envelope around the execution payload for L2. +#[derive(Debug, Clone)] +pub struct ExecutionPayloadEnvelope { + /// The execution payload. + pub payload: L2ExecutionPayload, + /// A signature for the payload. + pub signature: Signature, + /// The hash of the payload. + pub hash: PayloadHash, + /// The parent beacon block root. + pub parent_beacon_block_root: Option, +} + +impl ExecutionPayloadEnvelope { + /// Decode V1 + pub fn decode_v1(data: &[u8]) -> Result { + let mut decoder = snap::raw::Decoder::new(); + let decompressed = decoder.decompress_vec(data)?; + let sig_data = &decompressed[..65]; + let block_data = &decompressed[65..]; + + let signature = Signature::try_from(sig_data)?; + + let payload = ExecutionPayloadV1SSZ::deserialize(block_data)?; + let payload = L2ExecutionPayload::from(payload); + + let hash = PayloadHash::from(block_data); + + Ok(ExecutionPayloadEnvelope { parent_beacon_block_root: None, signature, payload, hash }) + } + + /// Decode V2 + pub fn decode_v2(data: &[u8]) -> Result { + let mut decoder = snap::raw::Decoder::new(); + let decompressed = decoder.decompress_vec(data)?; + let sig_data = &decompressed[..65]; + let block_data = &decompressed[65..]; + + let signature = Signature::try_from(sig_data)?; + + let payload = ExecutionPayloadV2SSZ::deserialize(block_data)?; + let payload = L2ExecutionPayload::from(payload); + + let hash = PayloadHash::from(block_data); + + Ok(ExecutionPayloadEnvelope { parent_beacon_block_root: None, signature, payload, hash }) + } + + /// Decode V3 + pub fn decode_v3(data: &[u8]) -> Result { + let mut decoder = snap::raw::Decoder::new(); + let decompressed = decoder.decompress_vec(data)?; + let sig_data = &decompressed[..65]; + let parent_beacon_block_root = &decompressed[65..97]; + let block_data = &decompressed[97..]; + + let signature = Signature::try_from(sig_data)?; + + let parent_beacon_block_root = Some(B256::from_slice(parent_beacon_block_root)); + + let payload = ExecutionPayloadV3SSZ::deserialize(block_data)?; + let payload = L2ExecutionPayload::from(payload); + + let hash = PayloadHash::from(block_data); + + Ok(ExecutionPayloadEnvelope { parent_beacon_block_root, signature, payload, hash }) + } +} + +impl Default for ExecutionPayloadEnvelope { + fn default() -> Self { + Self { + payload: L2ExecutionPayload::default(), + // Generic signature taken from `alloy_primitives` tests. + // + // https://github.com/alloy-rs/core/blob/main/crates/primitives/src/signature/sig.rs#L614 + signature: Signature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap(), + hash: PayloadHash::default(), + parent_beacon_block_root: None, + } + } +} diff --git a/crates/net/src/types/mod.rs b/crates/net/src/types/mod.rs new file mode 100644 index 0000000..dc4bb92 --- /dev/null +++ b/crates/net/src/types/mod.rs @@ -0,0 +1,6 @@ +//! Common types for the Networking Crate. + +pub mod address; +pub mod enr; +pub mod envelope; +pub mod payload; diff --git a/crates/net/src/ssz.rs b/crates/net/src/types/payload.rs similarity index 88% rename from crates/net/src/ssz.rs rename to crates/net/src/types/payload.rs index 9e9a860..ea3f357 100644 --- a/crates/net/src/ssz.rs +++ b/crates/net/src/types/payload.rs @@ -1,15 +1,39 @@ -//! SSZ Types +//! Execution Payload Types +use alloy::primitives::{keccak256, B256}; use kona_primitives::L2ExecutionPayload; use ssz_rs::{prelude::*, List, Vector, U256}; /// A type alias for a vector of 32 bytes, representing a Bytes32 hash type Bytes32 = Vector; + /// A type alias for a vector of 20 bytes, representing an address type VecAddress = Vector; + /// A type alias for a byte list, representing a transaction type Transaction = List; +/// Represents the Keccak256 hash of the block +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +pub struct PayloadHash(B256); + +impl From<&[u8]> for PayloadHash { + /// Returns the Keccak256 hash of a sequence of bytes + fn from(value: &[u8]) -> Self { + Self(keccak256(value)) + } +} + +impl PayloadHash { + /// The expected message that should be signed by the unsafe block signer. + pub fn signature_message(&self, chain_id: u64) -> B256 { + let domain = B256::ZERO.as_slice(); + let chain_id = B256::left_padding_from(&chain_id.to_be_bytes()[..]); + let payload_hash = self.0.as_slice(); + keccak256([domain, chain_id.as_slice(), payload_hash].concat()) + } +} + /// The pre Canyon/Shanghai [ExecutionPayload] - the withdrawals field should not exist #[derive(SimpleSerialize, Default)] pub struct ExecutionPayloadV1SSZ { @@ -243,3 +267,18 @@ fn convert_uint(value: U256) -> Option { fn convert_tx_list(value: List) -> Vec { value.iter().map(|tx| alloy::primitives::Bytes::from(tx.to_vec())).collect() } + +#[cfg(test)] +mod tests { + use super::*; + use alloy::primitives::b256; + + #[test] + fn test_signature_message() { + let inner = b256!("9999999999999999999999999999999999999999999999999999999999999999"); + let hash = PayloadHash::from(inner.as_slice()); + let chain_id = 10; + let expected = b256!("44a0e2b1aba1aae1771eddae1dcd2ad18a8cdac8891517153f03253e49d3f206"); + assert_eq!(hash.signature_message(chain_id), expected); + } +} From 325e24e4f85a67a0f1e4ffbbe84b64f2373a93ef Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 15:32:46 -0400 Subject: [PATCH 14/16] fix(net): re-use op stack enr key --- crates/net/src/discovery/builder.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/net/src/discovery/builder.rs b/crates/net/src/discovery/builder.rs index fe1cf02..8074f13 100644 --- a/crates/net/src/discovery/builder.rs +++ b/crates/net/src/discovery/builder.rs @@ -10,6 +10,8 @@ use discv5::{ }; use eyre::Result; +use crate::types::enr::OP_CL_KEY; + /// Discovery service builder. #[derive(Debug, Default, Clone)] pub struct DiscoveryBuilder { @@ -45,7 +47,7 @@ impl DiscoveryBuilder { let opstack_data: Vec = opstack.into(); let key = CombinedKey::generate_secp256k1(); - let enr = Enr::builder().add_value_rlp("opstack", opstack_data.into()).build(&key)?; + let enr = Enr::builder().add_value_rlp(OP_CL_KEY, opstack_data.into()).build(&key)?; let listen_config = ListenConfig::from_ip(addr.ip.into(), addr.port); let config = ConfigBuilder::new(listen_config).build(); From 8f439a01d29a3f5f3684e2aca3d086efc6d09766 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 15:43:50 -0400 Subject: [PATCH 15/16] fix(net): docs lints --- crates/net/src/discovery/driver.rs | 2 +- crates/net/src/gossip/driver.rs | 2 +- crates/net/src/types/payload.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/net/src/discovery/driver.rs b/crates/net/src/discovery/driver.rs index 0a2d3a9..33b34bc 100644 --- a/crates/net/src/discovery/driver.rs +++ b/crates/net/src/discovery/driver.rs @@ -39,7 +39,7 @@ impl DiscoveryDriver { /// ## Errors /// /// Returns an error if the address or chain ID is not set - /// on the [DiscoveryBuilder]. + /// on the [crate::discovery::builder::DiscoveryBuilder]. /// /// ## Example /// diff --git a/crates/net/src/gossip/driver.rs b/crates/net/src/gossip/driver.rs index f5c5050..247ba92 100644 --- a/crates/net/src/gossip/driver.rs +++ b/crates/net/src/gossip/driver.rs @@ -14,7 +14,7 @@ pub struct GossipDriver { } impl GossipDriver { - /// Creates a new [SwarmWithAddr] instance. + /// Creates a new [GossipDriver] instance. pub fn new(swarm: Swarm, addr: Multiaddr) -> Self { Self { swarm, addr } } diff --git a/crates/net/src/types/payload.rs b/crates/net/src/types/payload.rs index ea3f357..751d6fc 100644 --- a/crates/net/src/types/payload.rs +++ b/crates/net/src/types/payload.rs @@ -34,7 +34,7 @@ impl PayloadHash { } } -/// The pre Canyon/Shanghai [ExecutionPayload] - the withdrawals field should not exist +/// The pre Canyon/Shanghai [L2ExecutionPayload] - the withdrawals field should not exist #[derive(SimpleSerialize, Default)] pub struct ExecutionPayloadV1SSZ { /// Block hash of the parent block @@ -92,7 +92,7 @@ impl From for L2ExecutionPayload { } } -/// The Canyon/Shanghai [ExecutionPayload] - the withdrawals field should be an empty [List] +/// The Canyon/Shanghai [L2ExecutionPayload] - the withdrawals field should be an empty [List] #[derive(SimpleSerialize, Default)] pub struct ExecutionPayloadV2SSZ { /// Block hash of the parent block @@ -142,8 +142,8 @@ pub struct Withdrawal { } impl From for L2ExecutionPayload { - /// Converts an ExecutionPayloadV2SSZ received via p2p gossip into an [ExecutionPayload] used by - /// the engine. + /// Converts an ExecutionPayloadV2SSZ received via p2p gossip into an [L2ExecutionPayload] used + /// by the engine. fn from(value: ExecutionPayloadV2SSZ) -> Self { Self { parent_hash: convert_hash(value.parent_hash), @@ -168,7 +168,7 @@ impl From for L2ExecutionPayload { } } -/// The Ecotone [ExecutionPayload] - Adds Eip 4844 fields to the payload +/// The Ecotone [L2ExecutionPayload] - Adds Eip 4844 fields to the payload /// - `blob_gas_used` /// - `excess_blob_gas` #[derive(SimpleSerialize, Default)] From e997f6a20167faf11102139a990ca9305ccd8cb0 Mon Sep 17 00:00:00 2001 From: refcell Date: Mon, 26 Aug 2024 15:46:38 -0400 Subject: [PATCH 16/16] fix(net): docs lints --- crates/net/src/gossip/handler.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/net/src/gossip/handler.rs b/crates/net/src/gossip/handler.rs index 7ec438e..9e9385a 100644 --- a/crates/net/src/gossip/handler.rs +++ b/crates/net/src/gossip/handler.rs @@ -8,8 +8,10 @@ use tokio::sync::watch::{channel, Receiver, Sender}; use crate::types::envelope::ExecutionPayloadEnvelope; /// 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. +/// 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;