From a33b79eb4e910dbc6f61ca8d7be5eacd1ab66ade Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:20:44 +0100 Subject: [PATCH 01/16] docs(book): start documenting ExExes --- book/SUMMARY.md | 3 + book/developers/developers.md | 2 +- book/developers/exex/exex.md | 22 ++++ book/developers/exex/hello-world.md | 175 +++++++++++++++++++++++++++ book/developers/exex/how-it-works.md | 26 ++++ 5 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 book/developers/exex/exex.md create mode 100644 book/developers/exex/hello-world.md create mode 100644 book/developers/exex/how-it-works.md diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 473a389dae6a..1a39a0d87591 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -73,4 +73,7 @@ - [`reth recover`](./cli/reth/recover.md) - [`reth recover storage-tries`](./cli/reth/recover/storage-tries.md) - [Developers](./developers/developers.md) + - [Execution Extensions](./developers/exex/exex.md) + - [How do ExExes work?](./developers/exex/how-it-works.md) + - [Hello World](./developers/exex/hello-world.md) - [Contribute](./developers/contribute.md) diff --git a/book/developers/developers.md b/book/developers/developers.md index e5bf7cde90de..9d8c5a9c6739 100644 --- a/book/developers/developers.md +++ b/book/developers/developers.md @@ -1,3 +1,3 @@ # Developers -Reth is composed of several crates that can be used in standalone projects. If you are interested in using one or more of the crates, you can get an overview of them in the [developer docs](https://github.com/paradigmxyz/reth/tree/main/docs), or take a look at the [crate docs](https://paradigmxyz.github.io/reth/docs). \ No newline at end of file +Reth is composed of several crates that can be used in standalone projects. If you are interested in using one or more of the crates, you can get an overview of them in the [developer docs](https://github.com/paradigmxyz/reth/tree/main/docs), or take a look at the [crate docs](https://paradigmxyz.github.io/reth/docs). diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md new file mode 100644 index 000000000000..e5db072f9aa3 --- /dev/null +++ b/book/developers/exex/exex.md @@ -0,0 +1,22 @@ +# Execution Extensions (ExEx) + +## What are Execution Extensions? + +Execution Extensions allow developers to build their own infrastructure that relies on Reth +as a base for driving the chain (be it [Ethereum](../run/mainnet.md) or [OP Stack](../run/optimism.md)) forward. + +Execution Extension is a task that derives its state from Reth's state. +Some examples of such state derives are rollups, bridges, and indexers. + +Read more about things you can build with Execution Extensions in the [Paradigm blog](https://www.paradigm.xyz/2024/05/reth-exex). + +## How to build an Execution Extension? + +Let's dive into how to build our own ExEx (short for Execution Extensions) from scratch, add tests for it, +and run on Holesky testnet. + +1. [How do ExExes work?](./how-it-works.md) +1. [Hello World](./hello-world.md) +1. [Tracking State](./tracking-state.md) +1. [Testing](./testing.md) +1. [Running](./running.md) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md new file mode 100644 index 000000000000..1fbf7f822afd --- /dev/null +++ b/book/developers/exex/hello-world.md @@ -0,0 +1,175 @@ +# Hello World + +Let's write a simple "Hello World" ExEx that emits a log every time new chain of blocks is committed, reverted, or reorged. + +### Create a project + +First, let's create a new project for our ExEx + +```console +cargo new --bin hello-world-exex +cd hello-world-exex +``` + +And add Reth as a dependency in `Cargo.toml` + +```toml +[package] +name = "hello-world-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 +``` + +### Default Reth node + +Now, let's jump to our `main.rs` and start by initializing and launching a default Reth node + +```rust,noplayground +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 + }) +} +``` + +You can already test that it works by running the binary and initializing the Holesky node in a custom datadir +(to not interfere with any instances of Reth you already have on your machine): + +```console +$ cargo run -- init --chain holesky --datadir data + +2024-06-12T16:48:06.420296Z INFO reth init starting +2024-06-12T16:48:06.422380Z INFO Opening storage db_path="data/db" sf_path="data/static_files" +2024-06-12T16:48:06.432939Z INFO Verifying storage consistency. +2024-06-12T16:48:06.577673Z INFO Genesis block written hash=0xb5f7f912443c940f21fd611f12828d75b53 +4364ed9e95ca4e307729a4661bde4 +``` + +### Simplest ExEx + +The simplest ExEx is just an async function that never returns. We need to install it into our node + +```rust,noplayground +use reth::api::FullNodeComponents; +use reth_exex::{ExExContext, ExExEvent, ExExNotification}; +use reth_node_ethereum::EthereumNode; +use reth_tracing::tracing::info; + +async fn hello_world_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( + "Hello World", + |ctx| async move { Ok(hello_world_exex(ctx)) }, + ) + .launch() + .await?; + + handle.wait_for_node_exit().await + }) +} +``` + +See that unused `_ctx`? That's the context that we'll use to listen to new notifications coming from the main node, +and send events back to it. It also contains all components that the node exposes to the ExEx. + +Currently, our ExEx does absolutely nothing by running an infinite loop in an async function that never returns. + +
+ +It's important that our ExEx never returns, and the future that `hello_world_exex` function creates never resolves. + +If you try running a node with an ExEx that exits, the node will exit as well. + +
+ +### Hello World ExEx + +Now, let's extend our simplest ExEx and start to actually listen to new notifications, log them, and send events back to the main node + +```rust,noplayground +use reth::api::FullNodeComponents; +use reth_exex::{ExExContext, ExExEvent, ExExNotification}; +use reth_node_ethereum::EthereumNode; +use reth_tracing::tracing::info; + +async fn hello_world_exex( + mut ctx: ExExContext, +) -> eyre::Result<()> { + while let Some(notification) = ctx.notifications.recv().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().number))?; + } + } + + Ok(()) +} + +fn main() -> eyre::Result<()> { + reth::cli::Cli::parse_args().run(|builder, _| async move { + let handle = builder + .node(EthereumNode::default()) + .install_exex( + "Hello World", + |ctx| async move { Ok(hello_world_exex(ctx)) }, + ) + .launch() + .await?; + + handle.wait_for_node_exit().await + }) +} +``` + +Woah, there's a lot of new stuff here! Let's go through it step by step. + +- First, we've added a `while let Some(notification) = ctx.notifications.recv().await` loop that waits for new notifications to come in. + - The main node is responsible for sending notifications to the ExEx, so we're waiting for them to come in. +- Next, we've added a `match ¬ification { ... }` block that matches on the type of the notification. + - In each case, we're logging the notification and the corresponding block range, be it a chain commit, revert, or reorg. +- Finally, we're checking if the notification contains a committed chain, and if it does, we're sending a `ExExEvent::FinishedHeight` event back to the main node using the `ctx.events.send` method. + +
+ +Sending an `ExExEvent::FinishedHeight` event is a very important part of every ExEx. + +It's the only way to communicate the main node that the ExEx has finished processing the specified height. + +
+ +What we've arrived at is the [minimal ExEx example](https://github.com/paradigmxyz/reth/blob/b8cd7be6c92a71aea5341cdeba685f124c6de540/examples/exex/minimal/src/main.rs) that we provide in the Reth repository. + +## What's next? + +Let's do something a bit more interesting, and see how you can track some state inside your ExEx. diff --git a/book/developers/exex/how-it-works.md b/book/developers/exex/how-it-works.md new file mode 100644 index 000000000000..c3d98c159a35 --- /dev/null +++ b/book/developers/exex/how-it-works.md @@ -0,0 +1,26 @@ +# How do ExExes work? + +ExExes are just [Futures](https://doc.rust-lang.org/std/future/trait.Future.html) that run indefinitely alongside Reth +– as simple as that. + +An ExEx is usually driven by and acts on new notifications about chain commits, reverts, and reorgs, but it can span beyond that. + +They are installed into the node by using the [node builder](https://reth.rs/docs/reth/builder/struct.NodeBuilder.html). +Reth manages the lifecycle of all ExExes, including: +- Polling ExEx futures +- Sending [notifications](https://reth.rs/docs/reth_exex/enum.ExExNotification.html) about new chain, reverts, + and reorgs from historical and live sync +- Processing [events](https://reth.rs/docs/reth_exex/enum.ExExEvent.html) emitted by ExExes +- Pruning (in case of a full or pruned node) only the data that have been processed by all ExExes +- Shutting ExExes down when the node is shut down + +# Pruning + +Pruning deserves a special mention here. + +ExExes **SHOULD** emit an [`ExExEvent::FinishedHeight`](https://reth.rs/docs/reth_exex/enum.ExExEvent.html#variant.FinishedHeight) +event to signify what blocks have been processed. This event is used by Reth to determine what state can be pruned. + +An ExEx will only receive notifications for blocks greater than the block emitted in the event. + +To clarify: if an ExEx emits `ExExEvent::FinishedHeight(0)` it will receive notifications for any `block_number > 0`. From 96d7515354d87721a395da39cde33d7879f84fe8 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:23:27 +0100 Subject: [PATCH 02/16] norun --- book/developers/exex/hello-world.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index 1fbf7f822afd..a57e0461105d 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -31,7 +31,7 @@ eyre = "0.6" # Easy error handling Now, let's jump to our `main.rs` and start by initializing and launching a default Reth node -```rust,noplayground +```rust,norun,noplayground use reth_node_ethereum::EthereumNode; fn main() -> eyre::Result<()> { @@ -60,7 +60,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,noplayground +```rust,norun,noplayground use reth::api::FullNodeComponents; use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_node_ethereum::EthereumNode; @@ -105,7 +105,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 to actually listen to new notifications, log them, and send events back to the main node -```rust,noplayground +```rust,norun,noplayground use reth::api::FullNodeComponents; use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_node_ethereum::EthereumNode; From 7c0c203d75e3d655253090bb7cfa9ef874c2e0d9 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:24:32 +0100 Subject: [PATCH 03/16] ignore --- book/developers/exex/hello-world.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index a57e0461105d..be25d60f5685 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -31,7 +31,7 @@ eyre = "0.6" # Easy error handling Now, let's jump to our `main.rs` and start by initializing and launching a default Reth node -```rust,norun,noplayground +```rust,norun,noplayground,ignore use reth_node_ethereum::EthereumNode; fn main() -> eyre::Result<()> { @@ -60,7 +60,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 +```rust,norun,noplayground,ignore use reth::api::FullNodeComponents; use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_node_ethereum::EthereumNode; @@ -105,7 +105,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 to actually listen to new notifications, log them, and send events back to the main node -```rust,norun,noplayground +```rust,norun,noplayground,ignore use reth::api::FullNodeComponents; use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_node_ethereum::EthereumNode; From 40215534ae9282570190266b22a475a9ffbd1b03 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:27:10 +0100 Subject: [PATCH 04/16] fix links --- book/developers/exex/exex.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index e5db072f9aa3..cf00bf28337a 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -3,7 +3,7 @@ ## What are Execution Extensions? Execution Extensions allow developers to build their own infrastructure that relies on Reth -as a base for driving the chain (be it [Ethereum](../run/mainnet.md) or [OP Stack](../run/optimism.md)) forward. +as a base for driving the chain (be it [Ethereum](../../run/mainnet.md) or [OP Stack](../../run/optimism.md)) forward. Execution Extension is a task that derives its state from Reth's state. Some examples of such state derives are rollups, bridges, and indexers. @@ -17,6 +17,3 @@ and run on Holesky testnet. 1. [How do ExExes work?](./how-it-works.md) 1. [Hello World](./hello-world.md) -1. [Tracking State](./tracking-state.md) -1. [Testing](./testing.md) -1. [Running](./running.md) From 1c1c38d6a5a1d2901b3417397973521c0a3c5e45 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:29:59 +0100 Subject: [PATCH 05/16] grammar --- book/developers/exex/hello-world.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index be25d60f5685..3bcd5349a8c2 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -164,7 +164,8 @@ Woah, there's a lot of new stuff here! Let's go through it step by step. Sending an `ExExEvent::FinishedHeight` event is a very important part of every ExEx. -It's the only way to communicate the main node that the ExEx has finished processing the specified height. +It's the only way to communicate to the main node that the ExEx has finished processing the specified height +and it's safe to prune the associated data. From 21ab44fbd4bbd44317e830e8d800509031759011 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:30:57 +0100 Subject: [PATCH 06/16] # pruning -> ## pruning --- book/developers/exex/how-it-works.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/how-it-works.md b/book/developers/exex/how-it-works.md index c3d98c159a35..e9608703548b 100644 --- a/book/developers/exex/how-it-works.md +++ b/book/developers/exex/how-it-works.md @@ -14,7 +14,7 @@ Reth manages the lifecycle of all ExExes, including: - Pruning (in case of a full or pruned node) only the data that have been processed by all ExExes - Shutting ExExes down when the node is shut down -# Pruning +## Pruning Pruning deserves a special mention here. From 615e286e9dda503143f22f64657de29b620a475c Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 12 Jun 2024 18:36:11 +0100 Subject: [PATCH 07/16] keep track of --- book/developers/exex/hello-world.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index 3bcd5349a8c2..f111344cf2f6 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -173,4 +173,4 @@ What we've arrived at is the [minimal ExEx example](https://github.com/paradigmx ## What's next? -Let's do something a bit more interesting, and see how you can track some state inside your ExEx. +Let's do something a bit more interesting, and see how you can keep track of some state inside your ExEx. From 7a35aee53aae27e65c8d926f9a8324a5360c92af Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:32:40 +0100 Subject: [PATCH 08/16] Update book/developers/exex/exex.md Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com> --- book/developers/exex/exex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index cf00bf28337a..6bf7f91947b9 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -6,7 +6,7 @@ Execution Extensions allow developers to build their own infrastructure that rel as a base for driving the chain (be it [Ethereum](../../run/mainnet.md) or [OP Stack](../../run/optimism.md)) forward. Execution Extension is a task that derives its state from Reth's state. -Some examples of such state derives are rollups, bridges, and indexers. +Some examples of such state derivations are rollups, bridges, and indexers. Read more about things you can build with Execution Extensions in the [Paradigm blog](https://www.paradigm.xyz/2024/05/reth-exex). From fa78ed061e4ee375b80ff0cd1a344dd400efffb8 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:33:16 +0100 Subject: [PATCH 09/16] Update book/developers/exex/how-it-works.md Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com> --- book/developers/exex/how-it-works.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/how-it-works.md b/book/developers/exex/how-it-works.md index e9608703548b..7fd179bf9155 100644 --- a/book/developers/exex/how-it-works.md +++ b/book/developers/exex/how-it-works.md @@ -21,6 +21,6 @@ Pruning deserves a special mention here. ExExes **SHOULD** emit an [`ExExEvent::FinishedHeight`](https://reth.rs/docs/reth_exex/enum.ExExEvent.html#variant.FinishedHeight) event to signify what blocks have been processed. This event is used by Reth to determine what state can be pruned. -An ExEx will only receive notifications for blocks greater than the block emitted in the event. +An ExEx will only receive notifications for block numbers greater than the block in the most recently emitted `FinishedHeight` event. To clarify: if an ExEx emits `ExExEvent::FinishedHeight(0)` it will receive notifications for any `block_number > 0`. From bb5d14055f39bb22b579334c494863f2d5686be8 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:34:23 +0100 Subject: [PATCH 10/16] Update book/developers/exex/exex.md Co-authored-by: Oliver --- book/developers/exex/exex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index 6bf7f91947b9..5534d89faae3 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -10,7 +10,7 @@ Some examples of such state derivations are rollups, bridges, and indexers. Read more about things you can build with Execution Extensions in the [Paradigm blog](https://www.paradigm.xyz/2024/05/reth-exex). -## How to build an Execution Extension? +## How do I build an Execution Extension? Let's dive into how to build our own ExEx (short for Execution Extensions) from scratch, add tests for it, and run on Holesky testnet. From 5d8464d37f90a73c619ff0f85ca120f6b3f1beaa Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:34:35 +0100 Subject: [PATCH 11/16] Update book/developers/exex/exex.md Co-authored-by: Oliver --- book/developers/exex/exex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index 5534d89faae3..493be4f292bd 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -13,7 +13,7 @@ Read more about things you can build with Execution Extensions in the [Paradigm ## How do I build an Execution Extension? Let's dive into how to build our own ExEx (short for Execution Extensions) from scratch, add tests for it, -and run on Holesky testnet. +and run it on the Holesky testnet. 1. [How do ExExes work?](./how-it-works.md) 1. [Hello World](./hello-world.md) From 240e0854e8cd2be6c804ce8bbbf4f30fc65d870a Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:34:43 +0100 Subject: [PATCH 12/16] Update book/developers/exex/hello-world.md Co-authored-by: Oliver --- book/developers/exex/hello-world.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index f111344cf2f6..5e4d4bdbcc63 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -1,6 +1,6 @@ # Hello World -Let's write a simple "Hello World" ExEx that emits a log every time new chain of blocks is committed, reverted, or reorged. +Let's write a simple "Hello World" ExEx that emits a log every time a new chain of blocks is committed, reverted, or reorged. ### Create a project From 10587100ca1d1f0463c772879030b434d65101e2 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:34:58 +0100 Subject: [PATCH 13/16] Update book/developers/exex/hello-world.md Co-authored-by: Oliver --- book/developers/exex/hello-world.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index 5e4d4bdbcc63..3ec1d644d325 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -95,7 +95,7 @@ Currently, our ExEx does absolutely nothing by running an infinite loop in an as
-It's important that our ExEx never returns, and the future that `hello_world_exex` function creates never resolves. +It's important that the future returned by the ExEx (`hello_world_exex`) never resolves. If you try running a node with an ExEx that exits, the node will exit as well. From 9cfb8f8116956f0104fca0309ea3d13d73d89548 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:35:08 +0100 Subject: [PATCH 14/16] Update book/developers/exex/hello-world.md Co-authored-by: Oliver --- book/developers/exex/hello-world.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index 3ec1d644d325..bc059f972f71 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -103,7 +103,7 @@ If you try running a node with an ExEx that exits, the node will exit as well. ### Hello World ExEx -Now, let's extend our simplest ExEx and start to actually listen to new notifications, log them, and send events back to the main node +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 reth::api::FullNodeComponents; From 5728ad87a480bb6b5a9e593eb1d3df332d0d0b28 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 13:37:19 +0100 Subject: [PATCH 15/16] changes after review --- book/developers/exex/exex.md | 2 +- book/developers/exex/hello-world.md | 32 ++++++++--------------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index 493be4f292bd..b4354d3502c1 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -5,7 +5,7 @@ Execution Extensions allow developers to build their own infrastructure that relies on Reth as a base for driving the chain (be it [Ethereum](../../run/mainnet.md) or [OP Stack](../../run/optimism.md)) forward. -Execution Extension is a task that derives its state from Reth's state. +An Execution Extension is a task that derives its state from changes in Reth's state. Some examples of such state derivations are rollups, bridges, and indexers. Read more about things you can build with Execution Extensions in the [Paradigm blog](https://www.paradigm.xyz/2024/05/reth-exex). diff --git a/book/developers/exex/hello-world.md b/book/developers/exex/hello-world.md index bc059f972f71..c3da13ac4cc8 100644 --- a/book/developers/exex/hello-world.md +++ b/book/developers/exex/hello-world.md @@ -7,15 +7,15 @@ Let's write a simple "Hello World" ExEx that emits a log every time a new chain First, let's create a new project for our ExEx ```console -cargo new --bin hello-world-exex -cd hello-world-exex +cargo new --bin my-exex +cd my-exex ``` And add Reth as a dependency in `Cargo.toml` ```toml [package] -name = "hello-world-exex" +name = "my-exex" version = "0.1.0" edition = "2021" @@ -66,9 +66,7 @@ use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_node_ethereum::EthereumNode; use reth_tracing::tracing::info; -async fn hello_world_exex( - mut ctx: ExExContext, -) -> eyre::Result<()> { +async fn my_exex(mut ctx: ExExContext) -> eyre::Result<()> { loop {} } @@ -76,10 +74,7 @@ fn main() -> eyre::Result<()> { reth::cli::Cli::parse_args().run(|builder, _| async move { let handle = builder .node(EthereumNode::default()) - .install_exex( - "Hello World", - |ctx| async move { Ok(hello_world_exex(ctx)) }, - ) + .install_exex("my-exex", |ctx| async move { Ok(my_exex(ctx)) }) .launch() .await?; @@ -95,7 +90,7 @@ Currently, our ExEx does absolutely nothing by running an infinite loop in an as
-It's important that the future returned by the ExEx (`hello_world_exex`) never resolves. +It's important that the future returned by the ExEx (`my_exex`) never resolves. If you try running a node with an ExEx that exits, the node will exit as well. @@ -111,9 +106,7 @@ use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_node_ethereum::EthereumNode; use reth_tracing::tracing::info; -async fn hello_world_exex( - mut ctx: ExExContext, -) -> eyre::Result<()> { +async fn my_exex(mut ctx: ExExContext) -> eyre::Result<()> { while let Some(notification) = ctx.notifications.recv().await { match ¬ification { ExExNotification::ChainCommitted { new } => { @@ -140,10 +133,7 @@ fn main() -> eyre::Result<()> { reth::cli::Cli::parse_args().run(|builder, _| async move { let handle = builder .node(EthereumNode::default()) - .install_exex( - "Hello World", - |ctx| async move { Ok(hello_world_exex(ctx)) }, - ) + .install_exex("my-exex", |ctx| async move { Ok(my_exex(ctx)) }) .launch() .await?; @@ -152,7 +142,7 @@ fn main() -> eyre::Result<()> { } ``` -Woah, there's a lot of new stuff here! Let's go through it step by step. +Woah, there's a lot of new stuff here! Let's go through it step by step: - First, we've added a `while let Some(notification) = ctx.notifications.recv().await` loop that waits for new notifications to come in. - The main node is responsible for sending notifications to the ExEx, so we're waiting for them to come in. @@ -170,7 +160,3 @@ and it's safe to prune the associated data.
What we've arrived at is the [minimal ExEx example](https://github.com/paradigmxyz/reth/blob/b8cd7be6c92a71aea5341cdeba685f124c6de540/examples/exex/minimal/src/main.rs) that we provide in the Reth repository. - -## What's next? - -Let's do something a bit more interesting, and see how you can keep track of some state inside your ExEx. From f232b1bb7dacb4a6c85656b2b95ff11f84a4b296 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 13 Jun 2024 14:15:59 +0100 Subject: [PATCH 16/16] minor error --- book/developers/exex/exex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index b4354d3502c1..0c3199bc8745 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -12,7 +12,7 @@ Read more about things you can build with Execution Extensions in the [Paradigm ## How do I build an Execution Extension? -Let's dive into how to build our own ExEx (short for Execution Extensions) from scratch, add tests for it, +Let's dive into how to build our own ExEx (short for Execution Extension) from scratch, add tests for it, and run it on the Holesky testnet. 1. [How do ExExes work?](./how-it-works.md)