Skip to content

Commit

Permalink
docs(exex): include code for ExEx book from real files (#11545)
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhirin authored Oct 8, 2024
1 parent a2cfa9e commit 3765dbe
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 85 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ jwttoken/
crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake-build-debug

# Rust bug report
rustc-ice-*
rustc-ice-*

# Book sources should be able to build with the latest version
book/sources/Cargo.lock
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
86 changes: 4 additions & 82 deletions book/developers/exex/hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,15 @@ 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

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
Expand All @@ -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<Node: FullNodeComponents>(mut _ctx: ExExContext<Node>) -> 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,
Expand All @@ -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<Node: FullNodeComponents>(mut ctx: ExExContext<Node>) -> eyre::Result<()> {
while let Some(notification) = ctx.notifications.next().await {
match &notification {
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:
Expand Down
9 changes: 9 additions & 0 deletions book/sources/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"

13 changes: 13 additions & 0 deletions book/sources/exex/hello-world/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions book/sources/exex/hello-world/src/bin/1.rs
Original file line number Diff line number Diff line change
@@ -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
})
}
20 changes: 20 additions & 0 deletions book/sources/exex/hello-world/src/bin/2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use reth::api::FullNodeComponents;
use reth_exex::ExExContext;
use reth_node_ethereum::EthereumNode;

async fn my_exex<Node: FullNodeComponents>(mut _ctx: ExExContext<Node>) -> 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
})
}
39 changes: 39 additions & 0 deletions book/sources/exex/hello-world/src/bin/3.rs
Original file line number Diff line number Diff line change
@@ -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<Node: FullNodeComponents>(mut ctx: ExExContext<Node>) -> eyre::Result<()> {
while let Some(notification) = ctx.notifications.try_next().await? {
match &notification {
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
})
}

0 comments on commit 3765dbe

Please sign in to comment.