From 3765dbe4707ba199f3bc85fc78d4ba7029276fdc Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Tue, 8 Oct 2024 11:46:53 +0100 Subject: [PATCH] docs(exex): include code for ExEx book from real files (#11545) --- .github/workflows/lint.yml | 12 ++- .github/workflows/unit.yml | 5 ++ .gitignore | 5 +- Cargo.toml | 1 + book/developers/exex/hello-world.md | 86 +--------------------- book/sources/Cargo.toml | 9 +++ book/sources/exex/hello-world/Cargo.toml | 13 ++++ book/sources/exex/hello-world/src/bin/1.rs | 9 +++ book/sources/exex/hello-world/src/bin/2.rs | 20 +++++ book/sources/exex/hello-world/src/bin/3.rs | 39 ++++++++++ 10 files changed, 114 insertions(+), 85 deletions(-) create mode 100644 book/sources/Cargo.toml create mode 100644 book/sources/exex/hello-world/Cargo.toml create mode 100644 book/sources/exex/hello-world/src/bin/1.rs create mode 100644 book/sources/exex/hello-world/src/bin/2.rs create mode 100644 book/sources/exex/hello-world/src/bin/3.rs diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4bab77b915ee..e8161557fde9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -30,7 +30,12 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - run: cargo clippy --bin "${{ matrix.binary }}" --workspace --features "${{ matrix.network }} asm-keccak jemalloc jemalloc-prof min-error-logs min-warn-logs min-info-logs min-debug-logs min-trace-logs" + - name: Run clippy on binaries + run: cargo clippy --bin "${{ matrix.binary }}" --workspace --features "${{ matrix.network }} asm-keccak jemalloc jemalloc-prof min-error-logs min-warn-logs min-info-logs min-debug-logs min-trace-logs" + env: + RUSTFLAGS: -D warnings + - name: Run clippy on book binary sources + run: cargo clippy --manifest-path book/sources/Cargo.toml --workspace --bins env: RUSTFLAGS: -D warnings @@ -128,7 +133,10 @@ jobs: - uses: dtolnay/rust-toolchain@nightly with: components: rustfmt - - run: cargo fmt --all --check + - name: Run fmt + run: cargo fmt --all --check + - name: Run fmt on book sources + run: cargo fmt --manifest-path book/sources/Cargo.toml --all --check udeps: name: udeps diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index a6663aea8843..1056a6fb58c8 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -42,6 +42,11 @@ jobs: --workspace --exclude ef-tests \ --partition hash:${{ matrix.partition }}/2 \ -E "!kind(test)" + - name: Run tests on book sources + run: | + cargo nextest run \ + --manifest-path book/sources/Cargo.toml --workspace \ + -E "!kind(test)" state: name: Ethereum state tests diff --git a/.gitignore b/.gitignore index 2d5d851a5055..00f776542422 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,7 @@ jwttoken/ crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake-build-debug # Rust bug report -rustc-ice-* \ No newline at end of file +rustc-ice-* + +# Book sources should be able to build with the latest version +book/sources/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 8c1ee8c4514c..b6eed127119b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,6 +148,7 @@ members = [ "testing/testing-utils", ] default-members = ["bin/reth"] +exclude = ["book/sources"] # Explicitly set the resolver to version 2, which is the default for packages with edition >= 2021 # https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index facb07e5307f..c1f3e5af9443 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -14,19 +14,7 @@ cd my-exex And add Reth as a dependency in `Cargo.toml` ```toml -[package] -name = "my-exex" -version = "0.1.0" -edition = "2021" - -[dependencies] -reth = { git = "https://github.com/paradigmxyz/reth.git" } # Reth -reth-exex = { git = "https://github.com/paradigmxyz/reth.git" } # Execution Extensions -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth.git" } # Ethereum Node implementation -reth-tracing = { git = "https://github.com/paradigmxyz/reth.git" } # Logging - -eyre = "0.6" # Easy error handling -futures-util = "0.3" # Stream utilities for consuming notifications +{{#include ../../sources/exex/hello-world/Cargo.toml}} ``` ### Default Reth node @@ -34,15 +22,7 @@ futures-util = "0.3" # Stream utilities for consuming notifications Now, let's jump to our `main.rs` and start by initializing and launching a default Reth node ```rust,norun,noplayground,ignore -use reth_node_ethereum::EthereumNode; - -fn main() -> eyre::Result<()> { - reth::cli::Cli::parse_args().run(|builder, _| async move { - let handle = builder.node(EthereumNode::default()).launch().await?; - - handle.wait_for_node_exit().await - }) -} +{{#include ../../sources/exex/hello-world/src/bin/1.rs}} ``` You can already test that it works by running the binary and initializing the Holesky node in a custom datadir @@ -63,26 +43,7 @@ $ cargo run -- init --chain holesky --datadir data The simplest ExEx is just an async function that never returns. We need to install it into our node ```rust,norun,noplayground,ignore -use reth::api::FullNodeComponents; -use reth_exex::{ExExContext, ExExEvent, ExExNotification}; -use reth_node_ethereum::EthereumNode; -use reth_tracing::tracing::info; - -async fn my_exex(mut _ctx: ExExContext) -> eyre::Result<()> { - loop {} -} - -fn main() -> eyre::Result<()> { - reth::cli::Cli::parse_args().run(|builder, _| async move { - let handle = builder - .node(EthereumNode::default()) - .install_exex("my-exex", |ctx| async move { Ok(my_exex(ctx)) }) - .launch() - .await?; - - handle.wait_for_node_exit().await - }) -} +{{#include ../../sources/exex/hello-world/src/bin/2.rs}} ``` See that unused `_ctx`? That's the context that we'll use to listen to new notifications coming from the main node, @@ -103,46 +64,7 @@ If you try running a node with an ExEx that exits, the node will exit as well. Now, let's extend our simplest ExEx and start actually listening to new notifications, log them, and send events back to the main node ```rust,norun,noplayground,ignore -use futures_util::StreamExt; -use reth::api::FullNodeComponents; -use reth_exex::{ExExContext, ExExEvent, ExExNotification}; -use reth_node_ethereum::EthereumNode; -use reth_tracing::tracing::info; - -async fn my_exex(mut ctx: ExExContext) -> eyre::Result<()> { - while let Some(notification) = ctx.notifications.next().await { - match ¬ification { - ExExNotification::ChainCommitted { new } => { - info!(committed_chain = ?new.range(), "Received commit"); - } - ExExNotification::ChainReorged { old, new } => { - info!(from_chain = ?old.range(), to_chain = ?new.range(), "Received reorg"); - } - ExExNotification::ChainReverted { old } => { - info!(reverted_chain = ?old.range(), "Received revert"); - } - }; - - if let Some(committed_chain) = notification.committed_chain() { - ctx.events - .send(ExExEvent::FinishedHeight(committed_chain.tip().num_hash()))?; - } - } - - Ok(()) -} - -fn main() -> eyre::Result<()> { - reth::cli::Cli::parse_args().run(|builder, _| async move { - let handle = builder - .node(EthereumNode::default()) - .install_exex("my-exex", |ctx| async move { Ok(my_exex(ctx)) }) - .launch() - .await?; - - handle.wait_for_node_exit().await - }) -} +{{#include ../../sources/exex/hello-world/src/bin/3.rs}} ``` Woah, there's a lot of new stuff here! Let's go through it step by step: diff --git a/book/sources/Cargo.toml b/book/sources/Cargo.toml new file mode 100644 index 000000000000..c04c8567f94d --- /dev/null +++ b/book/sources/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] +members = [ + "exex/hello-world", +] + +# Explicitly set the resolver to version 2, which is the default for packages with edition >= 2021 +# https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html +resolver = "2" + diff --git a/book/sources/exex/hello-world/Cargo.toml b/book/sources/exex/hello-world/Cargo.toml new file mode 100644 index 000000000000..e5d32a140549 --- /dev/null +++ b/book/sources/exex/hello-world/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "my-exex" +version = "0.1.0" +edition = "2021" + +[dependencies] +reth = { git = "https://github.com/paradigmxyz/reth.git" } # Reth +reth-exex = { git = "https://github.com/paradigmxyz/reth.git" } # Execution Extensions +reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth.git" } # Ethereum Node implementation +reth-tracing = { git = "https://github.com/paradigmxyz/reth.git" } # Logging + +eyre = "0.6" # Easy error handling +futures-util = "0.3" # Stream utilities for consuming notifications diff --git a/book/sources/exex/hello-world/src/bin/1.rs b/book/sources/exex/hello-world/src/bin/1.rs new file mode 100644 index 000000000000..794609bfd7d1 --- /dev/null +++ b/book/sources/exex/hello-world/src/bin/1.rs @@ -0,0 +1,9 @@ +use reth_node_ethereum::EthereumNode; + +fn main() -> eyre::Result<()> { + reth::cli::Cli::parse_args().run(|builder, _| async move { + let handle = builder.node(EthereumNode::default()).launch().await?; + + handle.wait_for_node_exit().await + }) +} diff --git a/book/sources/exex/hello-world/src/bin/2.rs b/book/sources/exex/hello-world/src/bin/2.rs new file mode 100644 index 000000000000..6ab5fc49650e --- /dev/null +++ b/book/sources/exex/hello-world/src/bin/2.rs @@ -0,0 +1,20 @@ +use reth::api::FullNodeComponents; +use reth_exex::ExExContext; +use reth_node_ethereum::EthereumNode; + +async fn my_exex(mut _ctx: ExExContext) -> eyre::Result<()> { + #[allow(clippy::empty_loop)] + loop {} +} + +fn main() -> eyre::Result<()> { + reth::cli::Cli::parse_args().run(|builder, _| async move { + let handle = builder + .node(EthereumNode::default()) + .install_exex("my-exex", |ctx| async move { Ok(my_exex(ctx)) }) + .launch() + .await?; + + handle.wait_for_node_exit().await + }) +} diff --git a/book/sources/exex/hello-world/src/bin/3.rs b/book/sources/exex/hello-world/src/bin/3.rs new file mode 100644 index 000000000000..21bd25a56dbf --- /dev/null +++ b/book/sources/exex/hello-world/src/bin/3.rs @@ -0,0 +1,39 @@ +use futures_util::TryStreamExt; +use reth::api::FullNodeComponents; +use reth_exex::{ExExContext, ExExEvent, ExExNotification}; +use reth_node_ethereum::EthereumNode; +use reth_tracing::tracing::info; + +async fn my_exex(mut ctx: ExExContext) -> eyre::Result<()> { + while let Some(notification) = ctx.notifications.try_next().await? { + match ¬ification { + ExExNotification::ChainCommitted { new } => { + info!(committed_chain = ?new.range(), "Received commit"); + } + ExExNotification::ChainReorged { old, new } => { + info!(from_chain = ?old.range(), to_chain = ?new.range(), "Received reorg"); + } + ExExNotification::ChainReverted { old } => { + info!(reverted_chain = ?old.range(), "Received revert"); + } + }; + + if let Some(committed_chain) = notification.committed_chain() { + ctx.events.send(ExExEvent::FinishedHeight(committed_chain.tip().num_hash()))?; + } + } + + Ok(()) +} + +fn main() -> eyre::Result<()> { + reth::cli::Cli::parse_args().run(|builder, _| async move { + let handle = builder + .node(EthereumNode::default()) + .install_exex("my-exex", |ctx| async move { Ok(my_exex(ctx)) }) + .launch() + .await?; + + handle.wait_for_node_exit().await + }) +}